call_sid addresses the call the whole time. Recordings, reports, and QoS
keyed on the sid therefore stay intact across the handoff.
This recipe wires the full path:
1
Route the number to an AI agent
Inbound calls on your DID land on a server-side agent. No code in your
process answers the phone.
2
Give the agent a tool to resolve the query
A custom HTTP tool (
lookup_order) lets the model read your systems. The
model can then answer with real data.3
Escalate to a human with context
The built-in
route_to_skill tool drops the live caller into an ACD skill
queue with a one-line summary screen-pop. The runtime stamps the call_sid
onto the handoff.4
Accept and bridge — same sid throughout
A human accepts. The engine bridges the caller. The
call_sid never
changes.The agent runs server-side, inside ClutchCall Voice. You configure the
agent and its tools once. You do not hold an audio bridge in your process for
this pattern. Your code shows up in two places only: the backend that your
lookup_order tool calls, and (optionally) the control-plane calls that
observe or steer the call.1. Route the number to an AI agent
Inbound routing is control-plane configuration, not SDK code. A DID (or a whole trunk) binds to anagent_id. Calls that land on it inherit that agent.
Set this binding on the number in the console, or provision it when you buy the
number. See Inbound calls and
Number provisioning.
After the DID points at your agent, the engine answers each inbound call
(early-media SDP, then a 200). The engine wires the audio bridge end-to-end.
The agent starts to talk. Nothing in your process has to be online for the
engine to answer the call.
2. Define the agent and its resolve-the-query tool
An agent is a small orchestration graph (its DAG). It has a system prompt, a speech pipeline, and a set of tools that the model may call mid-conversation. Author it in the console, or push it over the control-plane API. There is no SDK wrapper for the DAG itself (see Agent DAGs and Tool calling). Here the agent is a single streaming (speech-to-speech) node with one custom tool,lookup_order, plus the implicit call-control toolset every voice agent
gets for free:
Agent config (support-bot)
lookup_order tool is an HTTP tool. You declare its name, its
description, and an OpenAPI-style parameter schema. You point it at an endpoint
that you host. The model fills the parameters. The runtime makes the request
and feeds the JSON response back into the turn.
Tool: lookup_order (http)
- TypeScript
- Python
3. Escalate to a human — with context
You do not author the escalation tool.route_to_skill is part of the
implicit call-control toolset that every voice agent carries. A blind SIP
transfer hands the caller away. route_to_skill does not. It keeps the caller
on our leg. It pauses the AI’s audio. It plays hold music. It drops the caller
into the ACD ring for a skill. When a human answers, the engine bridges the
caller.
The model calls it with two fields:
string
required
The department to queue to, e.g.
SUPPORT, BILLING, HC_TRIAGE. Match the
department the caller asked for.string
A one-line reason the caller needs a human. This is the screen-pop the
receiving agent sees before they take the call.
POST https://engine.clutchcall.dev/api/acd/queue (emitted by the runtime)
SUPPORT skill. If no such
human is online, the picker queues the request. The picker returns the chosen
agent, so the model can say “connecting you to Ashwin now.” The
source_call_id is the same call_sid that the AI leg used. The summary
becomes the human’s screen-pop.
Accepting the offer
When the offer rings on a human agent’s desktop, the desktop confirms it with a call to the accept endpoint. That call clears the offer marker, stops the ring, and bridges the caller, on the samecall_sid:
- TypeScript
- Python
The context that survives the handoff today is the one-line
summary
screen-pop, plus the skill, the caller’s number, and the preserved
call_sid. A richer structured payload (full transcript, verified identity,
collected fields rendered as a screen-pop card) is a product-level capability
on the roadmap. The SDK does not ship it wired yet. Build the human-facing
card off the summary + source_call_id for now.4. The sid is the throughline
route_to_skill keeps the caller on our leg. The call_sid is therefore
stable from the first ring through the human conversation. Your control-plane
code can observe or steer the same call at any point with the ClutchCall
Voice SDK:
- TypeScript
- Python
- Model-driven (
route_to_skill) — the agent decides, mid-conversation, that it needs a human. It queues to a skill with a summary. This style is best when the AI owns the judgment call. - App-driven (
call.transfer) — your backend decides. It re-attaches the call to a different agent, or it REFERs the call to a phone number. This style is best when an external signal (a supervisor, a business rule) forces the handoff.
call_sid is unchanged. The recording (both legs), the
segmented call report (AI segment vs human segment), and the per-call QoS all
stay keyed to one call.
Related
AI ↔ human handoff
How the live audio moves from the AI leg to the human.
Tool calling
HTTP, MCP, and client tools, plus the built-in telephony tools, in full.
PBX & ACD
Skills, VDNs, and the picker that selects the human.
Handoffs
The concept model behind AI→human, transfer, and re-attach.
Transfer to a human
The one-call transfer snippet, on its own.
Outbound sales agent
The outbound sibling of this recipe.

