Skip to main content
A custom function is your own Python, running inside the conversation. It is the escape hatch: anything the built-in function types do not cover — an API call, a database lookup, a calculation, a write into another system. Custom functions are available on both WhatsApp and Instagram agents.

Function shape

Four rules the runtime enforces:
Every function begins with the @tool decorator followed by an async def. The function name here must match the Name field on the form.
This is what the model reads when deciding whether to call the function. Write it for the model: what it does, and when to use it. A vague docstring is the most common reason a function never gets called.
Nothing may sit above @tool. Put every import in the function body.
Always. Return a readable error dict rather than raising — a raised exception reaches the customer as a generic failure with nothing useful in it.

Parameters

Type-annotate every parameter. The model fills them from the conversation, and the Test Run tab reads the same signature to build its input fields. Name parameters after the value they hold — city, order_id — not data or value. The name is part of what the model uses to work out what to put there.

Direct Send

WhatsApp agents only.
Off by default. With Direct Send on, the function’s return value is sent to the customer as-is, with no second model call — so it must be exactly:
message is the text the customer receives, verbatim. With Direct Send off, the model reads your dict and writes its own reply, so any shape works.
Use Direct Send when the wording must be exact and unedited — a legal disclaimer, a reference number, an OTP. Leave it off when you want the agent to weave the result into a natural reply.

Execution timeout

5 to 120 seconds, default 30, set on the Basic tab. The process is terminated if it exceeds the limit. Set your own HTTP client timeout below it, as in the example above, so a slow API returns a clean error you control instead of being killed mid-call.

Secrets

x_secrets is a dict of every secret in your account’s Secrets Vault, already decrypted:
Never hardcode API keys or credentials in a function. Save them in the Secrets Vault and read them from x_secrets.Attribute access (x_secrets.api_key) raises AttributeError — it is a dict.

Conversation context

x_context is available in every function with no lookup. The phone number keys use the same names as the post-call function variables on voice agents.

The contact record

x_contact is this person’s CRM contact row, already loaded — querying it yourself only costs latency.
If the agent calls update_contact earlier in the same turn, x_contact reflects that change — a function running after it always sees the updated values, never stale ones.

Building and testing

Test Run executes the real function against the real systems it calls. Point it at a test record the first time, not a live customer’s order.

Secrets

Where credentials belong

Functions overview

The other function types