Tools
Let an agent call your API mid-conversation — check an order, book a slot, look up a balance.
A tool is an HTTP endpoint of yours that the agent may call while it is talking.
Tools live on the agent (tools, up to 10) rather than as their own resource.
{
"tools": [{
"name": "lookup_order",
"description": "Look up an order by its id. Use this when the caller asks about an order they have already placed.",
"parameters": [
{ "name": "order_id", "type": "string", "description": "The order id, e.g. AC-4417", "required": true, "in": "path", "path": "orderId" }
],
"speech": { "en-IN": "Let me pull that up.", "hi-IN": "मैं देखता हूँ।" },
"http": {
"url": "https://api.example.com/orders/{orderId}",
"method": "GET",
"auth": { "type": "bearer", "secretId": "..." },
"timeoutMs": 4000
}
}]
}The description is the contract
description is not documentation — it is what the model uses to decide whether
to call the tool at all. Write it as a trigger condition ("use this when the
caller asks about an order they have already placed"), not as a summary ("order
lookup endpoint"). The same goes for each parameter.
Speech lines matter more than they look
An HTTP call takes time, and silence on a phone line reads as a dropped call.
speech is what the agent says while it waits. Give one per language the agent
speaks; without it the caller hears nothing while your API thinks.
Keep timeoutMs honest — 1000–30000 is allowed, but anything past a few seconds
is a long silence even with a filler line.
Credentials are referenced, never inline
🔴 A tool may not carry a credential in its definition. auth.secretId points at
an entry in your secret store, and an authorization-style header written inline
is rejected outright.
Secrets are created in the dashboard under Developer → Secrets — the store is write-only, with no read-back path, and an API key cannot create one. That is deliberate: a credential that can be read back is a credential that leaks through whatever can read it.
URLs are checked when you save the agent and checked again at execution time after DNS resolution, so a hostname that resolves into private address space is refused both when it is written and when it is used.
Mock it before you build it
{ "mock": { "enabled": true, "response": { "status": "shipped", "eta": "Thursday" } } }With mock.enabled, the tool returns your canned response instead of calling
anything. Design the conversation first, build the endpoint second.
Built-in tools
end_call is available and is how an agent hangs up deliberately. transfer_call
and press_digit are reserved names — they are not built, and an agent
declaring them will not get the behaviour you expect.