Skip to main content
  • What: Transfer a call from your AI agent to a human agent’s phone number with <Dial> and <Number>.
  • Watch out: On a <Stream> with keepCallAlive="true", close your WebSocket when you transfer.
The simplest transfer. When your AI agent decides to transfer, return this XML. Plivo dials the phone number in <Number>:

How a DID Forward Works

DID forward in five steps. 1: the caller is on a call with your AI agent. 2: your app returns Dial with Number to Plivo. 3: Plivo calls the phone number. 4: the human agent answers. 5: the caller now talks to the human agent. DID forward in five steps. 1: the caller is on a call with your AI agent. 2: your app returns Dial with Number to Plivo. 3: Plivo calls the phone number. 4: the human agent answers. 5: the caller now talks to the human agent.
  • Plivo originates an outbound call from your AI agent’s leg to the human agent’s phone number
  • When the human agent answers, the two legs are bridged
  • The caller and the human agent are connected, and your AI agent leaves the call

Trade-offs of a DID Forward

Pros
  • Works with any phone - mobile, landline, or a softphone with a DID
  • Simple to set up - needs nothing from your network team
Cons
  • Outbound call cost - billed for the full duration of the transferred call
  • Agents need a real phone number
  • Less flexibility - no custom SIP headers, no routing to specific agent IDs or queues
  • No warm transfer - your AI agent can’t brief the human agent before the caller is connected. For that, use Option 3: Multiparty Call
A DID forward is also the fastest way to prove a transfer problem is not your application. If a transfer to a phone number connects but a SIP transfer to the same team doesn’t, the fault is on the SIP path — the firewall or the credentials — not in your XML.

If Your Call Is on a Live Audio Stream

This applies when your AI agent runs over audio streaming and the call is on a <Stream> with keepCallAlive="true". With keepCallAlive="true", the <Stream> element runs exclusively and subsequent XML executes only after the stream disconnects. Your transfer XML is subsequent XML, so it does not run while the stream is still open. If the WebSocket never closes, the transfer never runs.
Close your bot’s WebSocket when you decide to transfer. Keep keepCallAlive="true" — closing the socket is what lets the call continue to your transfer XML, not removing the attribute.
When your AI agent closes its WebSocket. Too early: the call ends; fix by adding Wait right after Stream. On time: the transfer works. Stays open: the transfer never runs; fix by closing the WebSocket when you transfer, or use Option 3. When your AI agent closes its WebSocket. Too early: the call ends; fix by adding Wait right after Stream. On time: the transfer works. Stays open: the transfer never runs; fix by closing the WebSocket when you transfer, or use Option 3. Add a <Wait> right after <Stream> in your answer XML. If your AI agent closes its WebSocket before your transfer arrives, the call waits for it instead of ending:
Set length to cover the time between your AI agent closing its WebSocket and your server calling Transfer a Call. See the Wait reference for its attributes. If you stop the stream through the API rather than closing the socket, trigger the transfer first, then send DELETE /v1/Account/{auth_id}/Call/{call_uuid}/Stream/. Stopping the stream first lets the leg continue to the end of the XML document it is already running, which can end the call instead of transferring it. streamTimeout defaults to 86400 seconds. Set it to a realistic ceiling for your call shape so a stream that never closes cannot hold a call open. If transfers still drop the call or never run, use Option 3: Multiparty Call instead. In a Multiparty Call, the caller’s call doesn’t run <Stream>, so nothing waits for the WebSocket to close.

Server-Initiated Handoff

Instead of waiting for your answer URL to return Dial XML, you can trigger the transfer programmatically with the Transfer a Call API, which points a live call leg at a new URL. That URL returns the same <Dial> XML shown above. For SIP auth forward, include sipAuthUsername and sipAuthPassword on <User>. For a warm transfer, where your AI agent briefs the human agent before the caller is connected, use Option 3: Multiparty Call.