Hosted functions
Hosted functions are project-scoped TypeScript handlers hosted by Wabery. Use them when a WhatsApp workflow needs server-side logic close to the conversation: quote calculators, order lookups, enrichment, routing decisions, or small tools that a Business Agent can call.
Functions are created as metadata first, then deployed from source. Deployments always remain inactive until you review and explicitly activate them. A function must be active and have a successful deployment before Wabery can invoke it.
Create and deploy
Section titled “Create and deploy”Open Build tools → Functions to inspect deployments and logs in the dashboard, or create and deploy from the CLI, SDK, or API:
wabery functions create \ --slug quote-customer \ --name "Quote customer" \ --trigger-type ANY_MESSAGE
wabery functions deploy fn_... --source ./quote-customer.tswabery functions update fn_... --active truewabery functions test fn_... --text "Can you quote this?"wabery functions logs fn_...const fn = await wabery.functions.create({ slug: "quote-customer", name: "Quote customer", triggerType: "ANY_MESSAGE",});
await wabery.functions.deploy(fn.id, { source: `export default async function handler(ctx) { ctx.log("received", ctx.event.type); return { output: { reply: "Thanks, we will follow up." } };}`,});
await wabery.functions.update(fn.id, { isActive: true });await wabery.functions.test(fn.id, { text: "Can you quote this?" });curl https://api.wabery.com/v1/functions \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "slug": "quote-customer", "name": "Quote customer", "trigger_type": "ANY_MESSAGE" }'
curl https://api.wabery.com/v1/functions/fn_.../deploy \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"source":"export default async function handler(ctx) { return { output: { ok: true } }; }"}'
curl -X PATCH https://api.wabery.com/v1/functions/fn_... \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"is_active":true}'trigger_type matches automation triggers: KEYWORD, WELCOME, or
ANY_MESSAGE.
Function source
Section titled “Function source”Export a default async handler. Wabery passes the normalized event and a scoped context object.
export default async function handler(ctx) { const profile = await ctx.data.get("profile"); await ctx.kv.put("last_event", ctx.event.type); ctx.log("message", ctx.event.text);
return { output: { ok: true, profile }, };}Context access is scoped to the authenticated project and contact. Functions are request/response handlers; keep them bounded and use logs for debugging rather than long-running work.
Expose as a tool
Section titled “Expose as a tool”Hosted functions can back a Meta Business Agent connector tool, or be exposed as an external MCP/tool call. External invocation is opt-in:
wabery functions update fn_... \ --expose-as-mcp-tool true \ --input-schema '{"type":"object","properties":{"orderId":{"type":"string"}}}'
wabery functions invoke fn_... --arguments '{"orderId":"ord_123"}'SDK equivalent:
await wabery.functions.update("fn_...", { exposeAsMcpTool: true, inputSchema: { type: "object", properties: { orderId: { type: "string" } }, },});
await wabery.functions.invoke("fn_...", { arguments: { orderId: "ord_123" },});To wire a Business Agent tool to hosted logic, create a connector tool with
backing_type: "HOSTED_FUNCTION" and backing_function_id: "fn_...".
API scopes
Section titled “API scopes”Use scoped API keys where possible:
| Scope | Allows |
|---|---|
functions:read |
List functions, fetch source, read invocation logs. |
functions:write |
Create, update, deploy, test, and delete functions. |
functions:invoke |
Invoke an exposed function as a tool. |
The CLI and MCP server use the same REST endpoints. MCP write tools require write mode and confirmation tokens for create, deploy, update, invoke, and delete actions.