You will build four voice agents on one phone number: a front desk that works out what the caller needs and hands them on, and three specialists — billing, technical support and sales — each with its own prompt and tools. One route is decided by a lookup instead of the model: a caller with an open ticket goes straight to technical support. Every hop is a handoff (agent to agent, same call). Putting the caller through to a person is a transfer. Whether to split one agent at all is covered in agent teams.

What you need

  • Provider keys for Deepgram and OpenAI (the models below).
  • A workspace secret NORTHWIND_API_KEY — the bearer token for your invoice and account-lookup endpoints. Publishing a tool that references a missing secret fails.
  • A phone number in full international format for sales to transfer to.
  • An imported, provisioned phone number for the front desk.
The build order is leaves first: a handoff target must have a published version before an agent pointing at it validates, and a tool must be published before it is attached.
1

Create and publish the billing desk

Billing carries one tool, defined inline. An inline tool on an agent is created and published as a real tool by the same request; read the config back and the entry holds its tool_id.Every specialist prompt says the routing is already decided. A specialist that re-asks “what are you calling about?” sends callers round the loop.
billing.json
The http operation’s response goes back to the model, which answers in its own words. See the http operation.
2

Create and publish technical support and sales

Technical support has no tools; its troubleshooting facts are in the prompt. Create and publish it the same way:
technical.json
Sales qualifies and then puts the caller through to an account executive. Its one tool takes no arguments; the description carries the policy for when to use it.
sales.json
A warm transfer holds the caller while the agent briefs the account executive on a second line; if the transfer fails or is declined, the caller returns to the sales agent (on_failure: "continue"). Transfers work on phone calls only. See transfer.
3

Build the routing tool

Whether a caller has an open ticket is a fact, so a tool tree decides it rather than the model. The handoff operation hands off from inside the tree.
route_by_open_ticket.json
What the tree relies on:
  • on_error: "continue" keeps a failing lookup from breaking the front desk: nothing is published, exists is false, and the else branch runs.
  • publish_fields fails the operation when a path is missing from the response. Have your endpoint always return open_ticket_id (null when nothing is open) — a null publishes as nothing and exists reads it as false.
  • Under context: "summary" the operation’s summary is a template you write, not something the model is asked to produce.
  • if is terminal. Nothing follows it; each branch ends the tool. The else speaks because the tool is otherwise silent by derivation.
Create, validate and publish it (target_agent_id is the published technical support desk):
4

Create the front desk

Each handoffs entry becomes a handoff_to_<name> tool, and the model routes on its description alone. Write descriptions as what belongs there, and put each ambiguous word in exactly one of them. The front desk’s prompt is mostly about what it must not answer.
front-desk.json
POST it to /v1/agents as in step 1. The context on each edge decides what the target starts with:Under summary the source agent writes the summary as an argument of the handoff tool, so the handover waits for that text. recent_turns and summary_prompt are refused outside summary. summary is not a privacy boundary: userdata and the tail always cross, and the full transcript is recorded. See context policies.message plays while the target loads and always finishes before the target’s greeting. Leave it out and the caller hears silence until the new greeting.Post-call analysis runs once per call on the agent that answered, over the whole call including every desk — that is why it sits on the front desk. See call analysis.
5

Add the return edges

A return edge is an ordinary handoffs entry on the specialist, pointing at the front desk. PATCH replaces the handoffs list whole and keeps every other field. Republish after the change:
Publish the front desk before this edge validates. Give technical support and sales the same edge. Nothing detects routing cycles; a call is capped at 25 handoffs, after which the model is told to say “I’m sorry, I can’t pass you to another assistant again on this call.”
6

Publish everything and assign the number

Validate and publish each agent, then assign only the front desk to the number. The agent on the number answers; the specialists are reached only through handoffs.
Rules across the team:
  • All members share a channel and pipeline (all cascade or all realtime), and video members the same avatar; a mismatched edge is an error at validate. Out of an expressive agent, every target must use the same TTS provider and model with expressive on.
  • Nothing checks voices match. Give every member the same tts block, or the caller hears a different voice per desk.
  • Recording is decided by the answering agent. Recording cannot start mid-call, so turn it on for the front desk; validate warns about mismatches. See recording.
  • A handoff enters the target’s current published version, unlike attached tools, which pin at the source agent’s publish. Republishing a specialist reaches the next handoff without touching the front desk.

Test it

Run the routing tool alone. POST /v1/tools/{tool_id}/run executes the draft against your real endpoint and returns ok, handed_off, tooldata and steps:
Outside a phone call {{system_vars.human_phone_number}} is empty, so this run, a web call and the dashboard test panel all take the else branch. Prove the then branch by ringing the number from a phone with an open ticket. Walk each hop in the browser. The agent editor’s test panel runs the published version, so republish after each edit. Say one sentence per desk (“my card was charged twice”, “the drill won’t charge”, “I want to kit out a new site”), then an ambiguous one (“I’ve got a problem with an order”) — that is the sentence your descriptions have to settle. The sales transfer cannot run on a web call; test it on the number. Read a real call back. GET /v1/calls/{session_id} returns team, events (one agent.handoff per hop, with the policy, the summary and what crossed) and transcript, where each item carries the agent_id and agent_version that produced it. The session itself names only the agent that answered.

Tuning routing

Routing quality is a description-writing problem; there is no threshold to adjust. Change one description at a time and read the next calls. Calls with reroutes above 1 are worth opening first. To hear a change before publishing it, pass agent_version: "draft" when you place a test call.

Next

Team patterns

Front desk, return edges, lookup routing and per-call teams as reference.

Context policies

What each context carries across a handoff, and what it costs.

The handoff operation

The handoff operation in full.