Defining one
The description is the whole thing
The model has nothing else to go on. It decides whether to call your action, and with what, entirely from what you write here. Weak:Parameters need descriptions too
Every parameter must say what it is, or the model will invent a value.order_id
with no description gets filled with something plausible-looking and wrong.
Placeholders
Use{{parameter_name}} in the URL or the body:
- Every placeholder must have a parameter behind it. A
{{order_id}}with no matching parameter would reach your API as the literal text{{order_id}}— failing in a way that looks like your bug rather than ours. - The body must still be valid JSON once the blanks are filled.
Values the platform fills
Some placeholders are filled by us from the conversation, not by the model, so a caller cannot talk the agent into sending a different one. They have a dot in the name, and you do not declare them as parameters.- They work in the path, the query, the body and in header values. The host must be written out in full — a placeholder before the path is refused.
- Header values take only these, never a model parameter.
- An unknown one, such as
{{call.nope}}, is refused when you save. - On text chat (WhatsApp chat and web chat) the
call.*values are empty; the rest still fill. Voice calls on every surface, WhatsApp calls and web voice included, fill them. A test from the editor orPOST …/actions/{id}/testhas no conversation, so only{{agent.id}}and{{workspace.id}}fill.
X-Call-Id, X-Conversation-Id, X-Agent-Id and
X-Workspace-Id headers (each only when known), so you get them without
editing a template. A header you set yourself with the same name wins, whatever its capitalisation
(x-call-id replaces X-Call-Id).
During a test chat
A test chat (POST /api/v1/agents/{id}/test-chat, or test_chat over MCP) runs
your actions for real. So your endpoint can tell, every action request in a test
chat carries an X-Test-Chat: true header and {{test.chat}} fills as true.
There is no call, so {{call.id}} and {{call.from}} are empty and X-Call-Id
is not sent. Check for the header and answer as normal without writing anything
— no order placed, no record created — so testing never changes your real data.
Outside a test chat the header is never sent.
A test chat can also be run as a call: send "mode": "call" (or mode on the
test_chat MCP tool). The turn then uses the agent’s call prompt, its call rules or
the built-in ones plus the speaking rules, on the model its calls use and, on your
own Gemini key, the thinking level a call uses, with no cards or buttons. It shows the
words a caller will be given, which is how to try Telugu wording before a call. It is
not the voice or the hearing, and not the call’s own tools such as transferring or
hanging up. It needs calling set up on the agent.
Only the API’s test chat is marked. A chat in the console’s Playground, a
live conversation and a test of a single action from the editor are not, and the
tools of an MCP server you have connected to the agent are not marked either.
Reserved names
These clash with the agent’s built-in tools and are refused:search_knowledge,
capture_lead, escalate_to_human, send_media, send_link.
Anything else you connect is namespaced, so no third-party tool can impersonate
one of the agent’s own.
Security
HTTPS only, checked twice
HTTPS only, checked twice
Once when you save it — so you hear about an
http:// address while looking
at the form — and again at call time.The URL is resolved before we fetch it
The URL is resolved before we fetch it
Validated and DNS-resolved, so an address cannot be used to reach a
private network from inside ours.
Your secret is encrypted and shown once
Your secret is encrypted and shown once
Stored encrypted, not readable from the dashboard, and never displayed again
after you save it.
Thirty calls per conversation, per hour
Thirty calls per conversation, per hour
Custom actions are the only tool that spends your money, so the cap is a
per-conversation one. A conversation is the unit a visitor controls, so it is
the unit that gets bounded — a workspace-wide cap would be one a single
visitor could exhaust for everybody.Thirty is far above any honest conversation. Checking an order, a booking and
a balance twice over is under ten.
Writing the endpoint
Four rules, in order of how much trouble they save.1
Check the shared secret first
Before parsing anything.
2
Require two facts, never one
An order number alone is guessable — they are usually sequential. Require the
number and something only the real customer knows, like the email on the
order.
3
Fail identically for "not found" and "wrong match"
4
Return the smallest useful object
Everything you return may end up spoken to the customer. Return the status
and the tracking link, not the whole order record with the customer’s address
and payment details in it.