Pre-call and post-call tools run in the order you list them. On-call tools use
description and when to tell the voice agent when to invoke them.
Node-based agents support all three tool phases. A start or
conversation node offers only the on-call tools named in its
data.tools,
alongside its transitions. Define those tools on the agent first, or save the
definitions and graph together. Keep End call disabled or absent: a flow
ends at its end nodes. See the Node.js editor cookbook.Configure tools in Agent Studio
Open an agent in Agent Studio, then choose Tools in the agent navigation. The main navigation becomes an icon rail while you work. Switch to Prompt to edit the conversation without losing your tool changes. The first tool opens automatically when you choose a phase. Test agent stays visible while you edit. Type@ in the prompt or a supported tool field to insert
available context. Variables and tool references are highlighted differently in
the prompt, and pre-call results are grouped under the tool that returned them.
- Choose Pre-call, On-call, or Post-call, then click HTTP request.
- Enter a unique tool name, an HTTP method, and your HTTPS endpoint. Expand Headers, Query parameters, or JSON body as needed.
- For on-call requests, open Inputs to add the values the
agent should collect. Each input has a name, type, description, and required
setting. Reference these values in your request with
{{ args.order_id }}. - Open Behavior to describe when an on-call tool should run and set conditions and failure handling. For an on-call or pre-call HTTP tool, choose Wait for result or Run in background. A background result goes back to the agent when it is ready.
- Click Save changes at the top of the agent workspace. Prompt and tool edits save together as one agent revision.
- Open the tool’s Test tab, supply sample inputs, and click Run test. Inspect the status, response time, returned fields, and full receipt.
Run test executes the saved tool against your real endpoint. It does not
place a phone call. Save your edits before testing a new version. If the agent
changed in another editor, reload it before running the test.
name from lookup_customer makes {{lookup_customer.name}} available in the
prompt and {{ vars.lookup_customer.name }} available to later requests. A
pre-call tool’s result can also
set the call’s voice and language.
Use Authentication & secrets to store a credential or select a stored
Bearer token. You can reference any stored secret in a header with
{{ secrets.crm_api_key }}. Secret values are never returned to the editor.
Pre-call and post-call tools run independently of the conversation’s LLM. Use
Move up and Move down to arrange their order. An on-call condition is
checked against call inputs and pre-call results before the conversation
starts. During the call, the tool’s When should the agent use it?
instructions tell the agent when to invoke it.
Supported actions such as ending a call or scheduling a callback appear under
Add preset for the phases they support. You can still edit nested
conditions and more complex argument schemas in the advanced JSON fields.
Default tools
New agents created in Agent Studio include two editable tools. Existing agents keep their current configuration. To add either tool to an existing agent, choose its phase and use Add preset. Duplicating an agent copies its saved tools, including any tools you disabled or removed.Greeting and local time
The greeting preset is an ordinary HTTP request you can inspect and customize. It runs without an LLM. Open Query parameters to changetimezone to an
IANA timezone such as Europe/London or America/New_York.
timezone is optional and defaults to Asia/Kolkata. Invalid or empty timezone
names return 400 with error.code: "invalid_timezone". Responses are not cached.
Example response
epoch is Unix time in seconds; datetime includes
the local UTC offset. Daylight-saving changes follow the selected timezone.
The preset selects greeting, farewell, date, time, weekday, weekend, timezone,
and period fields for your prompt. Type @ in First message, choose
greeting, then greeting to insert {{ greeting.greeting }}. For example:
{{ vars.greeting.date }} and the other selected
fields. The preset has a two-second timeout and continues the call if the
request fails. You can change these settings in Behavior. Current-time
values describe when the pre-call request ran; they do not update during the call.
End call
End call runs directly on the voice worker during a conversation. It does not make an HTTP request. The default requires confirmation before hanging up and keeps the agent’s Closing message. To configure it, choose On-call, then End call. Testing the tool by itself does not place or end a phone call.Connect your first tool
Use your workspace API key and an existing agent ID. Create an agent with the quickstart if you do not have one yet.Authorization: Bearer YOUR_API_KEY.
1. Define the request
Save this asorder-status.json. Replace https://api.example.com/orders/status
with your public HTTPS endpoint. This example sends {"order_id":"ORD-123"}
and expects a JSON response such as {"status":"shipped","eta":"Friday"}.
order-status.json
2. Save it on your agent
This creates or replaces onlyorder_status and leaves the agent’s other tools
as they are. The response is 200 OK with the updated agent, including its
tools and revision.
tools: [ ... ] when creating or updating an agent.
PATCH /v2/agents/{id} with tools replaces the entire list; use the
single-tool route above to change one entry. Set tools: [] to remove all tools.
3. Test without placing a call
vars, args, call, and analysis.
The response shows the condition verdict, masked request, response, transformed
result, promoted values, and missing template paths. For a pre-call tool it
also shows the call_settings a
call would take and warnings for any it would skip. Check status as well as
HTTP status: the test route can return 200 with a failed tool receipt.
Place a new call with this agent to try the conversation. Ask about an order;
the voice agent collects the ID, invokes the tool, and uses its result.
Synchronous and background tools
Setexecution separately on each on-call HTTP tool. You can mix both modes
on one agent. Pre-call HTTP tools can run in the background too; see
Run a slow lookup in the background.
For example, collect another detail while a slow delivery lookup runs:
customer_id in the call’s variables. The voice agent should acknowledge
that work is pending, keep asking useful questions, and confirm the outcome
only after receiving the final result. Do not ask it to repeat the same request
while the first one is running.
- A user interruption does not cancel an accepted background request.
- If the result arrives during the call, the voice agent can use it when ready.
- If the call ends first, the request continues and its result is available in tool receipts. It cannot be spoken to a caller who has left.
- Late results do not rewrite a
call.completedevent already delivered. Read receipts for the final result;call.processedis not a completion signal for background on-call tools. execution: "async"is rejected for builtins and post-call tools. Builtins decide things and run in step; post-call tools already run after the conversation.
speak_while is an optional short line spoken as a tool starts, such as
"Let me check that for you.". If you leave it empty, the agent speaks no
canned filler. An async tool still lets the voice agent continue the
conversation.
Before a call: fetch context or skip dialing
Personalize the greeting
Add this tool to your agent. Suppose the endpoint returns{"name":"Asha","plan":"Premium"}:
{"customer_id":"cus_42"} in the call’s variables. The selected fields
become customer_lookup.name and customer_lookup.plan.
Use {{customer_lookup.name}} in the agent’s first_message or system_prompt.
Inside another tool’s template, use {{ vars.customer_lookup.name }} instead.
The pre-call request runs before dialing, before answering an incoming call,
or before opening browser audio.
On an incoming call the caller is already ringing, so pre-call tools get about
two seconds in total. A tool still running when that time is up counts as a
timeout and follows its on_failure rule: with "continue" the call is
answered without that tool’s values, and with "abort" it is not answered.
On incoming calls, {{ vars.caller_number }} and {{ vars.called_number }}
are available to look the caller up. Keep incoming-call lookups fast. Move
slower work to a background pre-call tool,
which doesn’t count against the two seconds, or to an on-call tool with
execution: "async" (background tools).
on_failure: "abort" prevents the call if this lookup fails. Nothing is
dialed, or the incoming caller is not answered, and the call ends failed
with ended_reason: "precall-tool-failed". The default, "continue", lets the
call go ahead, so if you keep it, write the greeting to handle missing values.
Set the voice and language for the call
A pre-call tool can choose the voice and the languages of the call it runs before. Put acall_settings object at the top level of the tool’s result. The
result is the response after response.transform, the same object select
reads, and without a transform it is the response body your endpoint sent.
If your endpoint answers:
sameer and listens for Gujarati and English from its
first word. The keys and their rules are the same as on
POST /v2/calls.
With a transform, you can turn any API’s answer into call settings without
changing that API. This tool calls a public echo service and builds
call_settings from what it echoes back:
sameer and Gujarati, and {{echo.word}} reads PINEAPPLE
in the prompt. call_settings is not a variable itself unless select names
it.
- Only a pre-call HTTP tool that waits for its result and succeeds sets
anything. A failed or skipped tool sets nothing, and a
background tool’s
call_settingsare ignored because it answers after the call has started. - Tools run in order, and a later tool wins for each key it sets.
nullmeans not set, so a transform that maps a missing field leaves the call’s value as it was.- A value we can’t use never fails the call. That covers a
call_settingsthat is not an object, a key with the wrong type, an unknown key and a value that breaks the rules. The call keeps the value it had, and the tool’s receipt says what was skipped. - The call object names the tool that chose
each value, such as
"voice_id": "pre_call:echo".
GET /v2/calls/{id}/tool_runs shows
the keys the call took in call_settings and anything skipped in warnings:
A receipt with one key skipped
call_settings
against the agent the same way and returns call_settings and warnings, so
you can see what a call would take before you place one.
Skip when a condition holds
aborted with ended_reason: "skipped-by-condition". A
campaign contact becomes skipped and is not retried as a failed attempt. Use
it alongside your workspace do-not-call list.
Run a slow lookup in the background
Set"execution": "async" on a pre-call HTTP tool when the lookup is slow and
the call should not wait for it. It starts at the same moment as the other
pre-call tools, and the call is dialed, or the incoming caller answered,
without waiting for it. On an incoming call it does not count against the
two-second budget.
- Its receipt is in
GET /v2/calls/{id}/tool_runswithphase: "pre_call", and the live events show it finishing. - Its selected values join the call’s variables. On-call tool requests can
read them as
{{ vars.caller_history.open_ticket }}, and so can post-call tools and the analysis prompt. - If the phone or browser call is still going, the agent gets the new values and uses them from its next reply. It does not speak up just because they arrived.
- It can’t stop the call, so
on_failuremust be"continue". Decide whether a call happens with a tool that waits, usingon_failure: "abort"or askip_call. - It can’t set the voice or language. Its
call_settingsare ignored, and its receipt says so inwarnings. - Nothing decided before it answers may read its values. A waiting pre-call
tool’s request or condition,
skip_call’s condition or reason, and an on-call tool’s condition may not usevars.<tool>.<key>ortools.<tool>of a background tool. Saving such an agent returns400 invalid_toolswith the path. An on-call tool’s request and post-call tools may read them. - It reads the call’s own variables only, such as
vars.caller_number. All pre-call tools start together, so the others’ outputs don’t exist yet. - Its values can’t fill
first_messageorsystem_prompt. Those are filled in before the call starts, so its placeholders there would be empty.
timeout_ms for a slow lookup. A tool that fails or runs
out of time leaves its receipt and nothing else.
If the call ends before the tool answers, the agent never hears the values.
They are still saved with the call, but post-call tools and analysis that
started before the answer arrived run without them. A skip_call or an
abort that stops the call before it starts also cancels the background
tool.
Conditions and templates
condition decides whether a tool is available or runs. when is a
natural-language instruction that tells the voice agent when to choose an
on-call tool.
all, any, and not. Supported operators are:
Conditions support up to eight nested levels and 64 comparisons. Use
exists
or not_exists when checking for a missing value.
Pre-call and post-call conditions are evaluated before each tool runs. The set
of available on-call tools is chosen when the call is prepared, after pre-call
outputs exist, so base an on-call condition on call inputs and pre-call
results. Finishing one on-call tool does not make new tools available, and
model arguments are not available when the initial tool list is chosen.
Values you can reference
Write
{{ vars.customer_id }} to insert text. Inside request.body, an entire
value such as "{{= args.quantity }}" preserves its JSON type instead of
converting it to a string. A missing text value renders empty and is listed
in the receipt; a missing typed value becomes null.
Filters are default:"value", json, and urlencode, for example
{{ vars.customer_name | default:"there" }}. Use request.query for query
parameters; values are URL-encoded automatically.
Test a condition without calling an external endpoint:
Store credentials as workspace secrets
Store a secret before saving a tool that references it:GET /v2/secrets returns names and timestamps, never values. Requests and
results shown in receipts mask resolved secret values. Keep credentials out of
prompts, call variables, and literal tool definitions.
To rotate a credential, PUT the new value to the same secret name. To delete
it, remove references from your agents first, then call
DELETE /v2/secrets/crm_key; a referenced secret returns 409.
After a call: send the outcome to your CRM
analysis.summary, analysis.success, analysis.data.* and, with templates,
analysis.template.*. Use a condition on
analysis.status or analysis.success when the request requires a successful
analysis result.
Receive call.processed
The terminal event, such as call.completed, describes the finished call.
call.processed reports the subsequent analysis and post-call tool results. It
is emitted when the agent has post-call tools or analysis enabled, unless you
set emit_processed_webhook: false on the agent. That setting turns off only
the event. Analysis and post-call tools still run.
The event uses your call’s webhook_url and the normal
webhook signature verification.
Alongside data.call, it includes:
Processing portion of a call.processed event
data.processing. post_call_tools is done, partial,
failed, or none; analysis is done, failed, skipped, or not_enabled.
A tool skipped by its condition is not a processing failure. Webhook retries
can change delivery order, so handle events by their type and processing version.
Rerun post-call tools
call.processed version. It does not rewrite the earlier event.
It returns 409 if the call has not finished or processing is already running.
Schedule a callback
Add this minimal builtin to let the voice agent arrange a later call:at argument and optional note to
the model. at should be a future RFC3339 timestamp with a UTC offset, such as
2026-10-01T15:00:00+05:30. Ask the customer to clarify an ambiguous time.
If you supply a custom description or parameters, we keep them.
The default window is at least 30 minutes and at most 14 days ahead. Change it
with builtin.min_delay_minutes and builtin.max_days. For a post-call
callback, configure builtin.at and optionally builtin.note as templates.
The new call targets the same person at the same tier and uses ordinary call
admission and billing. It carries parent_call_id and a callback_note input.
A scheduled callback can fail if the agent is no longer available or the
workspace cannot place the call at that time.
The tool result includes a callback_id. Cancel before dialing:
404. Schedule callbacks only with the customer’s agreement and observe your
calling-window and consent requirements.
Inspect tool results
data array contains receipts with the tool name, phase, status,
tool_run_id, start/end times, duration in milliseconds, HTTP status, transformed
result, and any error. Receipts can also include the condition verdict, masked
request, missing paths, and warnings. A pre-call receipt also has the
call_settings the call took from
that tool. Read these when a tool was skipped, timed out, returned an
unexpected result, or finished after hangup.
Use GET /v2/tools/catalog to discover supported tools, available phases,
execution modes, limits, and whether your configured model accepts structured
tool arguments. Builtins currently include:
An explicit
end_call tool can use builtin.enabled, builtin.message, and
builtin.confirm to override the agent’s ending settings.
Its tool-level enabled and condition also control whether it is available.
transfer_call and send_dtmf are listed as unavailable. Saving an unavailable
builtin returns tool_unavailable.
Tool definition reference
Requests support
GET, POST, PUT, PATCH, and DELETE. GET and DELETE
requests cannot carry a body. If a POST, PUT, or PATCH tool omits its body,
the model’s arguments become the body. Do not set transport-owned headers
Host, Content-Length, Transfer-Encoding, or Connection.
Responses with non-2xx status fail. JSON is parsed automatically; non-JSON
becomes {"text":"..."} unless response.strict is true. A jq transform
selects the result returned to the voice agent. response.select promotes
fields for use by later lifecycle steps; it does not replace transform for
narrowing the result the voice agent receives.
Limits and retries
You can define up to 40 tools per agent. On-call execution is limited to
40 runs per call and four concurrent requests per call. The pre-call phase has
a 30-second total budget, and about two seconds on an incoming call; background
pre-call tools are outside both. The post-call tool phase has a five-minute
budget, separate from any wait for analysis.
- Endpoints must use public HTTPS on port 443. Private-network destinations and redirects are refused.
- Request and response bodies are limited to 256 KB; URLs to 2,048 characters; headers and query entries to 20 each.
- jq transforms have a 100 ms budget and 64 KB output limit. Up to 16 selected fields can be promoted, each with a maximum value length of 512 characters.
- Retries apply to timeouts, connection failures, and server errors. Client errors, blocked destinations, and transform failures are not retried.
- Tool executions currently have no separate charge. Calls and callbacks use the normal call pricing; your API provider may charge separately.
Validation and runtime errors
Invalid tool definitions return400 with a list of field errors. This shape
differs from the API’s usual error envelope:
error can also be tool_unavailable or tool_style_unsupported. Fix the
listed fields before retrying. On a node-based agent, invalid node tool
references or an enabled end_call tool use the same shape with
error: "invalid_flow"; see
node-based agent errors. Ordinary authentication, lookup, and conflict
errors keep the standard error shape.
At runtime, inspect the receipt for errors such as timeout, http_429,
http_500, egress_denied, redirect_refused, transform_failed,
response_too_large, rate_limited, or budget_exhausted. An on-call tool
failure is returned to the voice agent so it can explain the problem and
continue the conversation.