Skip to content

Transfer Action

Transfer the call to another phone number.

Action Structure

json
{
  "type": "transfer",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "target_phone_number": "1234567890",
  "caller_id_name": "Support Department",
  "caller_id_number": "1234567890",
  "timeout": 30
}

Fields

FieldTypeRequiredDescription
typestringYesAlways "transfer"
session_idstring (UUID)YesSession identifier from event
target_phone_numberstringYesPhone number to transfer to (E.164 format without leading + recommended)
caller_id_namestringYesCaller ID name to display
caller_id_numberstringYesCaller ID number to display
timeoutinteger (5–120)NoSeconds to wait for the transfer target to answer. When set, enables transfer fallback (see below). When omitted, transfer failures end the call.

Transfer Fallback

When timeout is provided, the call is returned to the agent if the transfer fails:

  • Target does not answer within timeout seconds
  • Target rejects the call (busy, unavailable)
  • Target hangs up without answering

On a failed transfer, the service re-emits a session_start event with the same session.id, carrying a transfer_failed_reason. The agent can then continue the conversation with the original caller or attempt another transfer.

transfer_failed_reasonMeaning
busyThe target was busy
rejectedThe target actively declined the call
no_answerThe target rang until timeout expired without picking up
number_not_foundThe target number does not exist
technical_errorThe call could not be delivered for technical reasons
unknownThe outcome could not be determined

The first three mean the target was reachable but did not take the call, so trying another target usually makes sense. The last three point at the number or the route, where a retry rarely helps.

If you transfer again and that attempt fails too, you get another session_start — the reason always describes the most recent attempt.

On a successful transfer, no further events are sent — the call ends normally once the transferred parties hang up. Because a connected transfer never returns the caller, the absence of a returning session_start is the success signal, and there is no success reason to report.

The returning event looks like this:

json
{
  "type": "session_start",
  "session": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "account_id": "account-123",
    "phone_number": "1234567890",
    "direction": "inbound",
    "from_phone_number": "9876543210",
    "to_phone_number": "1234567890"
  },
  "transfer_failed_reason": "no_answer"
}

Treat a session_start that carries transfer_failed_reason as "the call came back" and respond with a recovery prompt (for example: "Sorry, no one picked up. Would you like to try something else?"). The field is absent on a new call, so you do not need to track which sessions you transferred.

Examples

Python

python
@app.route('/webhook', methods=['POST'])
def webhook():
    event = request.json

    if event['type'] == 'user_speak':
        user_text = event['text'].lower()

        if 'sales' in user_text:
            return jsonify({
                'type': 'transfer',
                'session_id': event['session']['id'],
                'target_phone_number': '1234567890',
                'caller_id_name': 'Sales Department',
                'caller_id_number': '1234567890'
            })

Node.js

javascript
app.post('/webhook', (req, res) => {
  const event = req.body;

  if (event.type === 'user_speak') {
    const userText = event.text.toLowerCase();

    if (userText.includes('sales')) {
      return res.json({
        type: 'transfer',
        session_id: event.session.id,
        target_phone_number: '1234567890',
        caller_id_name: 'Sales Department',
        caller_id_number: '1234567890'
      });
    }
  }
});

Go

go
if strings.Contains(text, "sales") {
    action := map[string]interface{}{
        "type":              "transfer",
        "session_id":        session["id"],
        "target_phone_number": "1234567890",
        "caller_id_name":    "Sales Department",
        "caller_id_number":   "1234567890",
    }
    json.NewEncoder(w).Encode(action)
}

Phone Number Format

Use E.164 format without leading + (recommended):

  • 1234567890
  • 491234567890
  • 123-456-7890 (not recommended)

Use Cases

  • Route to departments - Sales, support, billing
  • Escalate to human - When AI can't help
  • Specialized services - Connect to experts
  • Emergency routing - Urgent situations

Best Practices

  1. Announce transfer - Tell user before transferring
  2. Use E.164 format - International phone numbers
  3. Set caller ID - Identify the source
  4. Log transfers - Track routing decisions

Next Steps