zoxaAI
Homepage

Call Transfer Tool

Configure blind call transfers to phone numbers or SIP endpoints, allowing your voice agent to hand off calls to human agents or other destinations.

What you'll learn

  • How blind (unattended) call transfers work
  • Which telephony providers support transfers
  • How to configure the transfer destination, pre-transfer message, and timeout
  • What happens during and after the transfer

The Call Transfer tool performs a blind transfer during a live call. When the LLM decides a transfer is needed (based on the tool's description and conversation context), the platform initiates the transfer to the configured destination and disconnects the AI from the call.


How It Works

The caller says something that matches the tool's description (e.g., "Can I speak to a manager?").

The LLM triggers the transfer tool.

If a pre-transfer message is configured, it is spoken or played first.

The platform initiates a blind transfer to the destination number or SIP endpoint.

The AI disconnects from the call. The caller is now connected directly to the destination.

This is a blind transfer (also called an unattended transfer). The call is forwarded without first confirming the destination is available. If the destination does not answer within the timeout period, the call may go to voicemail or disconnect depending on the telephony provider's behavior.


Supported Telephony Providers

Call transfer support depends on the telephony provider handling the call:

ProviderPhone Number TransferSIP TransferDestination FormatBridging Mechanism
TwilioYesNoE.164 (e.g., +14155551234)Conference: destination dials in, then the A-leg's TwiML is updated to join the same conference.
VobizYesNoE.164 (e.g., +919876543210)A-leg redirect: the active call leg is repointed to a new <Dial> XML answer URL, no conference needed.
PlivoYesNoE.164A-leg redirect (legs=aleg): the live call is repointed to a new <Dial> XML answer URL.
TelnyxYesNoE.164Linked dial: the destination is dialed as a new leg sharing the call session (link_to) and auto-bridged to the caller at answer (bridge_on_answer).
VonageYesNoE.164Named conversation: the destination is dialed into a conversation "room", and the caller's leg is moved into the same conversation when they answer.
CloudonixYesNoE.164Application switch (cold transfer): the live session's voice application is replaced with a <Dial> to the destination.
Tata SmartfloYes (blind)NoE.164Platform-side blind transfer (/v1/call/options type 4) — the Tata platform owns the bridge.
Asterisk ARIYes (via SIP)YesPJSIP/SIP endpoints (e.g., PJSIP/1234)Native ARI bridge swap.

WebRTC-only calls (browser calls) do not support call transfer because there is no telephony leg to transfer. Call transfer requires an active telephony connection — all eight telephony providers support it.

Caller-ID on the transfer leg

The destination always sees the agent's phone number on caller ID, not the original caller's number. The platform picks this up automatically from the call's direction:

  • Outbound calls → the number the agent dialed from is used as the CID.
  • Inbound calls → the DID the user dialed into is used as the CID.

This matches every business-friendly use case: a caller who reaches your support line shouldn't have their own number forwarded to whoever you transfer them to.


Configuration Reference

Common Fields

FieldTypeConstraintsDescription
namestringMax 255 charactersDescriptive name for the tool (e.g., "Transfer to Support"). The LLM sees this name.
descriptionstring--Tells the LLM when to transfer the call. This is the primary signal for tool selection.

Example description:

Use this tool when the caller asks to speak with a human agent, requests to be transferred, or when you cannot resolve their issue and they need human assistance.


Transfer Destination

FieldTypeFormatDescription
destinationstringE.164 or SIPThe phone number or SIP endpoint to transfer to.

The destination supports two formats:

FormatPatternExampleUsed With
Phone numberE.164 international+14155551234All telephony providers
SIP endpointAsterisk-style SIP URIPJSIP/1234 or SIP/[email protected]Asterisk ARI

You can toggle between phone number and SIP mode in the dashboard using the link below the destination input.

Phone numbers must be in E.164 format (starts with +, followed by country code and number, no spaces or dashes). Example: +14155551234 for a US number, +442071234567 for a UK number.


Pre-Transfer Message

Controls what happens before the transfer is initiated.

FieldTypeValid ValuesDefaultDescription
messageTypestring"none", "custom", "audio""none"Whether to play a message before transferring.
customMessagestring or null--nullText to speak before transfer (when messageType is "custom").
audioRecordingIdstring or null--nullRecording ID of a pre-recorded audio file (when messageType is "audio").

Message Options

OptionBehavior
No Message ("none")Transfer immediately without any announcement.
Custom Message ("custom")Speak a text message before transferring. The text is synthesized by the agent's TTS provider and spoken as-is. Example: "Please hold while I transfer your call."
Pre-recorded Audio ("audio")Play a pre-recorded audio file before transferring. Use this for polished hold messages or multilingual announcements.

When using a custom text message, the text is synthesized by whatever TTS provider is configured on the agent. Phrase it carefully for multilingual use cases -- the TTS engine will read it exactly as written.


Transfer Timeout

FieldTypeRangeDefaultDescription
timeoutinteger5 -- 120 seconds30Maximum time to wait for the transfer destination to answer.

If the destination does not answer within the timeout, the behavior depends on the telephony provider:

ProviderTimeout Behavior
TwilioCall may go to voicemail or disconnect, depending on Twilio's configuration.
Asterisk ARICall is typically disconnected. Behavior depends on your Asterisk dialplan.

Tool Definition Schema

The full JSON schema for a Call Transfer tool definition:

{
  "schema_version": 1,
  "type": "transferCall",
  "config": {
    "destination": "+14155551234",
    "messageType": "custom",
    "customMessage": "Please hold while I transfer your call to our support team.",
    "audioRecordingId": null,
    "timeout": 30
  }
}

Example: Transfer to Support Team

Configuration:

  • Name: Transfer to Support
  • Description: Use this tool when the caller asks to speak with a human agent, requests to be transferred to support, or when you cannot resolve their issue.
  • Destination: +18005551234
  • Message Type: Custom
  • Custom Message: I'm transferring you to our support team now. Please hold for a moment.
  • Timeout: 30 seconds

What happens during a call:

  1. Caller: "I'd like to speak with someone about my billing issue."
  2. LLM recognizes the transfer intent and triggers the tool.
  3. Agent says: "I'm transferring you to our support team now. Please hold for a moment."
  4. The platform initiates a blind transfer to +18005551234.
  5. The AI disconnects. The caller hears ringing and is connected to the support team.

What Happens After the Transfer

The platform waits for the destination to actually answer before letting go of the call:

  • The AI agent stays on the line while the destination's phone is ringing. The pipeline does not end until the destination picks up — so a no-answer or busy doesn't kill the original call mid-ring.
  • The caller hears ringing as the transfer destination's phone rings — the platform's hold music where the caller stays on our stream (Twilio, Telnyx, Vonage, ARI), or carrier-delivered hold/ringback for redirect-style providers (Vobiz, Plivo, Cloudonix, Smartflo).
  • If the destination answers, the bridge is set up provider-side (conference for Twilio, linked dial for Telnyx, conversation for Vonage, A-leg redirect for Vobiz/Plivo), the agent's pipeline closes cleanly, and the caller is now connected directly. This is a normal phone call between the caller and the destination.
  • If the destination does not answer (busy, no-answer, failed, timed out), the agent does not drop the call. Instead the LLM is told the transfer failed and can verbalize the outcome — "Sorry, no one picked up. Is there anything else I can help with?" — so the conversation continues.
  • The call record is updated with the transfer event, including the destination number, timestamp, and the result.

`end_call` is gated during an in-flight transfer

If the LLM tries to call end_call in the same response as transfer_call, the platform refuses the end_call until the transfer reaches a terminal state. This prevents the pipeline from closing prematurely between "transfer initiated" and "destination answered".

Because this is a blind transfer, the AI doesn't supervise the new call once the destination answers and the bridge takes over. If you need guaranteed human availability, consider validating agent schedules before offering transfer as an option (via your tool description).


Recording the Transfer

Two flags decide what gets captured on the carrier's side. Both default to a sensible value, so you don't have to set them unless you want to override. The transfer tool's Record Transferred Call toggle in the dashboard maps to recordTransfer.

FlagWhereDefaultWhat it controls
recordInProviderConsoleCall config (agent / snapshot)false (off — Zoxa already records the call itself)When true, the carrier records the entire call (pre + post transfer) into one file in their console.
recordTransfertransferCall tool configtrue (on)When true and recordInProviderConsole is false, the carrier records just the transfer leg (from destination answer to hangup).

With both defaults untouched, a transfer is tail-recorded out of the box: recordInProviderConsole defaults off and recordTransfer defaults on, so an API caller who never mentions either flag gets the transferred conversation recorded and attached to the call automatically.

Automatic download to the call record

When a transfer-leg recording is captured, the platform fetches it from the carrier after the transferred conversation ends and stores it with the call:

  1. At transfer time the call row records the transfer correlation (transfer_id, provider, destination, B-leg ID).
  2. When the carrier signals the recording is ready (Twilio's conference recordingStatusCallback, Vobiz/Plivo <Record> completion callbacks, Telnyx's call.recording.saved event, Vonage's record event, Cloudonix's Dial recording callback, ARI teardown, Smartflo CDR), a background job downloads the media with the call's own provider credentials.
  3. The file is re-hosted in platform storage and appended to the call's recordings as a kind: "transfer" entry.
  4. The call detail page then shows a second player — Transferred Call Recording — below the main one, with its own playback-speed control and download. The GET /calls/{callId} response includes the entry (as a signed URL) only when the recording exists.
  5. If the call has a webhook configured, a call.transfer_recording.completed event fires with the recording link and the same callId as the earlier lifecycle events — so your receiver can attach the late artifact to the right call.

Because the transferred conversation can continue long after the agent leaves the call, the transfer recording typically appears in call history minutes after the main recording. If the carrier never produces a file (for example the transfer was too short) or the file can't be downloaded, the entry never appears — and a configured webhook receives call.transfer_recording.failed with the reason instead.

Cascade

recordInProviderConsolerecordTransferWhat lands in the carrier console
true(any)One full-call recording. Captures pre-transfer (agent ↔ user) and post-transfer (user ↔ destination) in a single file. The per-transfer flag is ignored to avoid producing a second, redundant recording of the transfer leg.
falsetrueOne transfer-leg recording. Captures the user ↔ destination conversation from the moment the destination answers.
falsefalseNo carrier-side recording. (zoxa's own S3 recording is independent of these flags.)

What the caller hears while the destination rings

After the optional pre-transfer message, the caller hears the platform's hold music until the destination answers, rejects, or the transfer times out — at which point the music stops immediately (they're either bridged to the human, or the agent comes back to explain the failure). The agent does not hear the caller during this window (user input is muted for the duration of the transfer attempt).

How the hold music is delivered depends on the provider:

ProviderHold music mechanism
TwilioPlayed by the agent pipeline (the caller stays on our media stream until the destination answers)
TelnyxPlayed by the agent pipeline (the caller stays on our stream until Telnyx bridges the legs at answer)
VonagePlayed by the agent pipeline (the caller stays on our websocket leg until moved into the transfer conversation)
ARI (Asterisk)Played by the agent pipeline (same — the bridge swap happens on answer)
VobizPlayed by the carrier via the Dial dialMusic XML attribute, fetched from the platform
PlivoPlayed by the carrier via the Dial dialMusic XML attribute, fetched from the platform
CloudonixNot controllable — the application switch detaches the caller immediately; they hear standard carrier ringback
SmartfloNot controllable — the blind transfer hands the bridge to the Tata platform, which plays its own ringback

Pre-answer ring audio

No provider's transfer recording captures the pre-answer ring audio on the transfer leg — recording starts the instant the destination picks up. The "from ringing" you might see in other platforms typically refers to Twilio's machine-detection feature, not to ring-back capture.

Provider support matrix

The two flags above only do something when the underlying telephony provider supports the relevant primitive. Use this table to set realistic expectations per provider.

ProviderCall transfersrecordInProviderConsole (full call)recordTransfer (transfer leg)Auto-attached to call record
Twilio✓✓ via POST /Calls/{Sid}/Recordings.json✓ via <Conference record="record-from-start"> + recording status callback✓ (MP3, downloaded when Twilio reports the file ready)
Vobiz✓✓ via POST /v1/Account/{id}/Call/{uuid}/Record/✓ via <Record startOnDialAnswer="true"> before the <Dial> (recording starts at answer, so ring/hold audio is excluded)✓ (MP3, downloaded on the RecordStop callback)
Plivo✓✓ via POST /v1/Account/{id}/Call/{uuid}/Record/✓ via <Record startOnDialAnswer="true"> before the <Dial> (recording starts at answer, so ring/hold audio is excluded)✓ (MP3, downloaded on the Record completion callback)
Telnyx✓✓ via POST /v2/calls/{id}/actions/record_start✓ via record: record-from-answer on the transfer dial (scoped to the destination leg)✓ (MP3, re-resolved through the Recordings API — Telnyx webhook URLs expire in 10 minutes)
Vonage✓Not available (Vonage mid-call NCCO update would drop the active connect)✓ via a record action on the destination's NCCO (spans the whole transferred conversation)✓ (MP3, JWT-authenticated download; Vonage retains recordings 30 days)
Cloudonix✓ (cold)Not available (live-call recording endpoint not documented)✓ via <Dial record="record-from-answer"> on the transfer CXML✓ (downloaded from the Dial recording callback URL)
ARI (Asterisk)✓Partial — channel recording via POST /ari/channels/{id}/record (captures one side only per the Asterisk docs note about channel vs bridge recording)✓ via bridge recording (POST /ari/bridges/{id}/record, mixed two-party audio)✓ (WAV, pulled from Asterisk's stored recordings at teardown)
Smartflo✓ (blind)n/a (recording is a platform-side account setting; no per-call API)Partial — no per-leg control; when the toggle is on, the platform CDR recording is fetched after the call. Per Tata's docs it covers the initial leg and the first transfer in one file.✓ (MP3, when the account has recording enabled)

Where full-call carrier recording is marked Not available (Vonage, Cloudonix), setting recordInProviderConsole=true is logged as "skipped" by the runner and the call proceeds normally — the flag is harmless, just inactive. zoxa's own S3 recording is independent of all of this and continues to work on every provider.

What gets captured per cascade row (provider-aware)

Combining the cascade with the provider matrix, the practical outcomes per provider:

  • Twilio, Vobiz, Plivo, Telnyx: full cascade behavior — both flags do exactly what they describe, and the transfer-leg file is auto-attached to the call record.
  • Vonage, Cloudonix: recordTransfer works and the file is auto-attached; recordInProviderConsole (full-call carrier recording) is not available, so zoxa's S3 recording is the only full-call copy.
  • ARI: recordInProviderConsole=true records the user's channel only (Asterisk's note about channel vs bridge); the transfer leg, however, is recorded properly as mixed bridge audio when recordTransfer is on.
  • Smartflo: recording is controlled on the Tata side (account/route settings), not per call. With recordTransfer on, the platform fetches the CDR recording after the call — note it spans the whole call (initial leg + first transfer), since that is how Tata records.

Where to find the recording

The transferred-call recording appears on the call detail page as a second player under the main recording, once the background fetch completes. The carrier-side IDs remain visible in the tool-call Outcome block on the Transcript tab:

  • Transfer SID → the transfer leg's carrier ID (Twilio B-leg CallSid / Vobiz BLegCallUUID), useful for cross-referencing in the carrier console.
  • Original SID → the original caller's leg, useful when recordInProviderConsole is true (the full-call recording is indexed by this).

Transfer Outcome Reasons

Every transfer ends with one of the following reason values inside the transferCall tool result. The same value is emitted on the call.completed webhook's tool entry. Two categories — carrier-reported outcomes and tool-side errors — with different semantics.

Carrier-reported outcomes

These mean the transfer attempt ran end-to-end and the telephony provider reported a definitive result. The tool itself succeeded; the destination just didn't get bridged. Use these to drive your post-transfer business logic (retry, queue, voicemail fallback, etc.).

reasonTwilio CallStatus sourcePlivo/Vobiz DialStatus sourceMeaning
no-answerno-answerno-answer, timeoutThe destination's phone rang past the configured timeout without being picked up.
busybusybusyThe destination's line was busy.
failedfailedfailedThe carrier couldn't route the call — typically an invalid number or unreachable destination.
canceledcanceledcancelThe transfer leg was cancelled before the destination answered (e.g., the caller hung up the original leg during ring).

All four use Twilio's canonical spelling (no-answer with hyphen, canceled with one L) so a single parser handles both providers. The accompanying transfer_call_sid lets you cross-reference the carrier's console.

Tool-side errors

These indicate the transfer attempt never completed. Either the platform refused to dial, the provider rejected our request, or the carrier never reported back. Treat them as bugs to triage, not customer-facing outcomes.

reasonSourceMeaning
execution_errorTool handler caught an unexpected exceptionInvestigate logs by call_id.
provider_not_supportedThe telephony provider's supports_transfers() returned False, or its credentials failed validate_config()Misconfigured provider or missing capability.
web_call_not_supportedA transferCall tool was invoked on a web (browser) callDon't expose the tool on web calls.
no_destinationThe tool was registered without a destination fieldFix the agent config.
transfer_in_progressA concurrent transfer was already running for this callShould be rare — the LLM emitted two transfer_call requests in parallel.
timeoutThe wait for the carrier's status callback timed out (default 30s)The carrier never reported a definitive outcome. Check that your provider can reach our webhook URL and that Redis pub/sub is healthy.

Status interpretation

  • result.status === "success" plus action: "destination_answered" — the destination picked up. The agent's pipeline is closing; the caller is now in the human conversation.
  • result.status === "transfer_failed" plus any of the carrier-reported reasons above — the tool succeeded but the bridge didn't form. The agent continues; the LLM verbalizes the outcome to the caller.
  • result.status === "transfer_failed" plus a tool-side error reason — the tool itself failed. The agent continues; treat as an internal alert.

Best Practices

  1. Write clear trigger descriptions -- the LLM decides when to transfer based on the description. Be explicit about what phrases or scenarios should trigger a transfer.
  2. Always use a pre-transfer message -- even a simple "Please hold while I transfer your call" prevents the caller from experiencing unexpected silence.
  3. Set appropriate timeouts -- 30 seconds is usually sufficient. Increase for call centers with longer queue times.
  4. Use E.164 format -- always include the country code with a + prefix. Never use local number formats.
  5. Test the destination number -- verify the number is correct and reachable before deploying the tool to production.

On this page