transfer hands the caller to a human being on a phone number. It is the escape hatch every voice agent needs: the question the agent cannot answer, the caller who has asked three times for a person, the account that has to be opened by someone with a login.
Phone calls only. On a web call or a text conversation the operation fails with “transfer is only available on phone calls”. This is not caught when you publish, because the same tool may be attached to a phone agent and a chat agent — it fails on the call, and the agent apologises and carries on.Transferring to another agent is not this operation. That is handoff.

The configuration

The destination is fixed at publish

destination is a literal number, frozen into the published tool version. It is never templated and never chosen by the model. {{args.number}} is refused at save, and so is a number the caller reads out.
This is a toll-fraud rule, not an oversight. A destination the model can write is a destination a caller can talk it into writing — a premium-rate line, an international number, anything. The published tool version is the only place a transfer destination is decidable, which makes every transfer on your account a deliberate, attributed, reviewable choice.If you need three destinations, publish three tools. That pattern is below, and it is better in every other respect too.
The number must already be canonical, not merely fixable. A bare 4155550101 is refused with the number we think you meant, rather than silently normalised against some default country:

What the caller experiences

How the person is reached is the platform’s business. We dial them into the call and step out; the caller does not hear a click, a menu, or anything to indicate which mechanism ran.
The person answering sees the workspace’s own number, not the caller’s. The leg to them is dialled from your workspace’s own carrier trunk, and a trunk can only present a number it owns. Caller ID for a transfer is trunk-level on every carrier and cannot be set per transfer.Plan for it: if the person answering needs to know who is calling, use warm, or put the caller’s number in the CRM record the same tool writes.

mode: cold or warm

This is the only choice you get about how a transfer runs, and it is about the caller’s experience rather than about plumbing. cold is the right default. The agent finishes its line, the caller hears hold music for as long as the other phone takes to ring, and a person answers. There is no introduction and no “let me hand you over to Sarah”. warm puts the caller on hold while the agent rings the person, tells them who is calling and what they want, answers whatever they ask, and only then puts the two together. The caller hears none of it. It suits escalation to a named colleague; it does not suit a busy queue, where the briefing is a minute of hold music per call for no benefit.

On warm, the person can decline

They can also turn out to be a voicemail greeting rather than a person. In both cases the transfer does not happen: the caller comes off hold, the agent is told in general terms why, and the conversation carries on exactly where it left off. The agent is never told — and therefore can never repeat — the words that person used. Their own explanation is kept on the call’s timeline, not in the caller’s ear.

While the caller is on hold

Their microphone and speaker are both switched off and hold music plays. That is deliberate: nobody is listening during a ring, so an open microphone would only bill speech-to-text for a caller saying “hello?” into it. Hold time sits inside the call’s duration, its recording and its bill, and the call’s timeline marks where it started and ended.

ringing_timeout

ringing_timeout (5–120 seconds, default 30) bounds the ringing, and nothing after it. Below five seconds no phone has finished its first ring; past 120 a caller has had time to hang up twice.
On warm, the briefing has a separate 90-second cap of its own — and both the ring and the briefing have to fit inside a 120-second carrier media timeout on the held caller’s line. The default 30-second ring plus a 90-second briefing lands exactly on 120.So raising ringing_timeout toward its maximum eats that margin, and a briefing that then runs long can cost you the held caller altogether. If you raise the ring, raise it a little.

on_failure

Busy line, nobody home, a declined warm transfer — on_failure decides what happens next.
  • continue (default) — the agent is told plainly why the transfer did not happen and keeps talking to the caller. Almost always what you want: the caller is still on the line and the agent can offer something else.
  • end_call — the call is ended, exactly as an end_call operation would end it.
What the agent is told is always plain English about the person being called, never a technical reason: That last line deliberately also covers failures on our own side — a trunk that is not authorised, a carrier having a bad day. The caller is never told the destination refused them when the fault was not theirs. The carrier’s own verdict is kept on the call record for whoever debugs the trunk. The agent is also instructed to report the failure and carry on helping, rather than restarting the conversation — which is what a model that has just watched a tool fail mid-turn otherwise does.

The line before the transfer

Put a say immediately before the transfer if the caller should hear something. There is no message field on the operation: a line before a transfer is an ordinary say, so it templates, it shows as its own node in the editor’s flowchart, and it reads the same way as a goodbye before an end_call. You do not need wait_for_playback on it. The transfer already waits for outstanding speech to finish before it dials. Unlike an end_call, “let me transfer you” is a promise the platform keeps, so say it here. Word it for the mode: Before a cold transfer, “let me speak to them first” is simply a lie: nobody is briefed and the caller lands on a stranger.

Tick disable_interruptions

Set the tool-level disable_interruptions flag on any transfer tool. The dial runs for up to ringing_timeout while the caller hears nothing but ringback, which is exactly long enough that saying “hello?” into the gap is the normal thing for a caller to do. An interrupted line is dead five seconds later, and that line is the only channel left to tell the caller what happened. With the flag on, the caller cannot talk over “connecting you now” and turn a waited line into an interrupted one.

Two shapes a transfer tool cannot have

Both are refused when you publish. It cannot be long_running_task. A background tool is detached from the turn that called it, so the handover would happen outside the turn that asked for it — mid-sentence, or not at all.
It cannot be a lifecycle hook. A hook runs outside a turn, so the agent cannot finish speaking before the handover. This one is caught when you publish the agent, because a hook tool is a perfectly valid tool on its own.

One tool per destination

If the caller could go to billing, sales or support, build three toolstransfer_to_billing, transfer_to_sales, transfer_to_support — each taking no arguments, each one say and one transfer. Do not build one transfer_to_department that branches on an argument. Three reasons, in order of how much they matter:
  1. The model picks a tool more reliably than it picks an enum value. Choosing between three named functions is the thing tool-calling models are best at. Filling in department: "billing" correctly is a strictly harder problem you have created for no reason.
  2. Every destination gets its own description, which is where the routing policy lives (below). One tool means one description covering three different escalation rules.
  3. The tool list reads like the org chart. Anyone opening the agent can see where a call can go. Five nested ifs inside one tool hide it.
There is no cost to the extra tools — a transfer tool is two operations — and nesting them in one tree is worse in every respect.

The description is the escalation policy

For every other kind of tool a weak description costs you a mis-timed API call. Here it decides whether a frustrated caller reaches a person, and how soon.
“Transfer to a human” invites the model to escalate at the first sign of difficulty. It is not a description, it is an invitation.
Write the policy instead:
Use only after you have tried to answer the question yourself and the caller has explicitly asked for a person, or is clearly distressed. Do not use it for questions about order status, delivery dates or returns — you can answer those.
Decide when escalation should happen before you write it, and put the answer in the description. That is the entire routing logic of the tool.

A complete transfer tool

transfer_to_billing: argument-free, one line, one transfer, interruptions off.
The warm equivalent changes two lines — the mode, and the line the caller hears:

After the transfer

Once the transfer connects, this call is over as far as the platform is concerned. The agent says nothing more, and the call’s duration and recording cover only the part the agent was on. The transfer.briefing entry is the only record of what your AI said about a customer to a third party, so it is kept as a compliance record rather than as telemetry. It is also where a declined transfer’s real reason lives.
A transferred call stays on your carrier’s clock until one of the two people hangs up. Two humans who both walk away from the phone will run to the three-hour call cap. See transfers for the operator’s view of a transferred call.

Next

Transfers in operation

Reading a transferred call, and what it costs.

Handoff operation

Moving the call to another agent instead of a person.

Schema and description

Writing a description the model can act on.

Patterns

The escalation recipe, and five more complete tools.