transfers:, and two forms.
On this page:
- How you write it - the block, and every key it takes
- The number is an environment variable - the model never sees a number
- The route decides what is possible - which shape compiles where
- The transfer has to be reachable - the half that is enforced
- When the person does not pick up -
ring_timeoutandon_unavailable - Where to go next - the two routes that carry a transfer
How you write it
A transfer is a block in thetransfers: list of the agent that offers it. Cold
is the default. Writing brief: makes it warm, so a warm only setting cannot be
written on a cold transfer:
agent.yaml
- send_to_billing. A bare name nobody
defines is refused, and so are two blocks with one name.
Transfer fields
string
required
A lower snake case name, unique across the package.
string
required
The UPPER_SNAKE name of an environment variable holding an E.164 number or a
sip: URI,
read at call time. Declare it in secrets:. No destination is inferred.string
The situation the model reads to decide whether to transfer. Omission supplies no
trigger guidance, so write one.
string
A positive Go duration, such as
25s. Omitted means 25 seconds on Pipecat; LiveKit
leaves it unset for the platform default.Accepts
return_to_caller or hangup. Omitted means return_to_caller. Pipecat
cloud-websocket requires explicit hangup, because the original media stream cannot be
reconnected.string
Instructions for briefing the person before connecting the caller. Makes the transfer
warm. Supported only on LiveKit SIP.
The number is an environment variable
The model never sees a phone number.to: names the variable that holds it, and
the variable goes in secrets::
agent.yaml
to: is refused. The refusal does not repeat the number:
agent.yaml rather than on the target because who this agent
transfers to is the same desk whichever carrier reaches it.
The route decides what is possible
Transfers ride the platform’s own primitive. There are three different mechanisms, which is why the answer differs per route:
Warm transfer is not supported on any Pipecat target. It requires the LiveKit
sip route.
Pipecat daily-sip + Twilio is the Daily shape that transfers, and the carrier
is why: your carrier owns the number and hands Daily the SIP leg, so there is a
real phone leg to hand on. A cold transfer there needs a Twilio connection and an
active channels.phone route; a browser session has no leg and gets a named
failure before the agent announces anything.
You hear a transfer on a deployed agent. Both shapes hand a real phone leg to
a real number, so there is no local rehearsal for either: deploy, finish the
carrier setup, and place the call. The browser loop that unmute dev gives you
covers the prompt, the tools and the models, and stops exactly where the phone
leg starts.
Read the two words in that table carefully, because they are different answers:
- yes means the compiler emits it, and a deployed call performs it.
- refused means the shape does not compile. The error names the connection, the transport it declares, and a route where the shape does work.
A target with no route at all
The table above is about which route does what. A target that names no connection is a separate case, and it is now refused too:daily-sip transfer needs a Twilio connection and an active channels.phone route.
A browser session has no SIP leg and gets a named
failure before the agent announces a transfer.
The transfer has to be reachable
A transfer block sits in one agent’stransfers: list. Another agent offers it by
listing the bare name. A bare name that no agent defines is refused at build, with
the file, the line, and the fix:
.env.example and the startup check for something nothing could
dial.
When the person does not pick up
sip route, no answer, a decline, voicemail, and a failed dial
all come back as one failure, and on_unavailable decides what happens next.
On the Pipecat cloud-websocket route, when the destination leg ends, Twilio
ends the original call. A decline or no answer also ends the call after the
dial timeout. No fresh agent starts without the previous conversation context.
Pipecat cloud-websocket requires explicit on_unavailable: hangup; it cannot
reconnect the original media stream.
The agent sees only the accepted REST update as transfer_started; it does not
observe whether the person answers.
Where to go next
LiveKit route
Cold and warm over a SIP trunk.
Pipecat on Twilio
Cold, with nothing hosted by you.