Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions fern/calls/call-dynamic-transfers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -339,18 +339,29 @@ sequenceDiagram
console.log(`Transfer request: ${department} - ${reason} (${urgency})`);

// Determine destination based on department
// Include transferPlan for warm transfers with context
let destination;
if (department === 'support') {
destination = {
type: "number",
number: "+1234567890"
number: "+1234567890",
transferPlan: {
mode: "warm-transfer-say-message",
message: `Incoming call about: ${reason}. Priority: ${urgency}.`
}
};
} else if (department === 'sales') {
destination = {
type: "number",
number: "+1987654321"
number: "+1987654321",
transferPlan: {
mode: "warm-transfer-wait-for-operator-to-speak-first-and-then-say-message",
message: `Hi, I have a customer interested in our products. Reason: ${reason}.`,
timeout: 30
}
};
} else {
// Default to blind transfer for general inquiries
destination = {
type: "number",
number: "+1555555555"
Expand Down Expand Up @@ -413,22 +424,33 @@ sequenceDiagram
print(f"Transfer request: {department} - {reason} ({urgency})")

# Determine destination based on department
# Include transferPlan for warm transfers with context
if department == 'support':
destination = {
"type": "number",
"number": "+1234567890"
"number": "+1234567890",
"transferPlan": {
"mode": "warm-transfer-say-message",
"message": f"Incoming call about: {reason}. Priority: {urgency}."
}
}
elif department == 'sales':
destination = {
"type": "number",
"number": "+1987654321"
"number": "+1987654321",
"transferPlan": {
"mode": "warm-transfer-wait-for-operator-to-speak-first-and-then-say-message",
"message": f"Hi, I have a customer interested in our products. Reason: {reason}.",
"timeout": 30
}
}
else:
# Default to blind transfer for general inquiries
destination = {
"type": "number",
"number": "+1555555555"
}

# Execute transfer via Live Call Control
async with httpx.AsyncClient() as client:
await client.post(
Expand All @@ -452,7 +474,7 @@ sequenceDiagram

<Note>
**SIP transfers:** To transfer to a SIP endpoint, use `"type": "sip"` with `"sipUri"` instead:

```json
{
"type": "transfer",
Expand All @@ -464,6 +486,19 @@ sequenceDiagram
}
```
</Note>

<Tip>
**Warm transfer modes:** The examples above show warm transfers using `transferPlan`. Available modes include:
- `blind-transfer` - Immediate transfer (default when no `transferPlan` is specified)
- `warm-transfer-say-message` - Say a custom message to the operator
- `warm-transfer-say-summary` - Say an AI-generated conversation summary
- `warm-transfer-wait-for-operator-to-speak-first-and-then-say-message` - Wait for operator response before delivering message
- `warm-transfer-wait-for-operator-to-speak-first-and-then-say-summary` - Wait for operator response before delivering summary
- `warm-transfer-twiml` - Execute custom TwiML instructions
- `warm-transfer-experimental` - Use a transfer assistant for intelligent handoffs

See [Live Call Control](/calls/call-features#5-transfer-call) and [Assistant-based warm transfer](/calls/assistant-based-warm-transfer) for more details.
</Tip>
</Step>

<Step title="Test your dynamic transfer system">
Expand Down
106 changes: 101 additions & 5 deletions fern/calls/call-features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,14 @@ curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/742
```

### 5. Transfer Call
Transfer the call to a different destination.
Transfer the call to a different destination. Transfers support both blind (immediate) and warm (with context) modes.

#### Blind Transfer (Default)
Immediately transfer the call without any context to the receiving party.

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
Expand All @@ -132,8 +135,8 @@ curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/742
You can also transfer to a SIP URI:

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
Expand All @@ -144,6 +147,99 @@ curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/742
}'
```

#### Warm Transfer
Provide context to the receiving party before connecting the customer. Use the `transferPlan` property to configure warm transfer behavior.

**Say a message before connecting:**

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
"type": "number",
"number": "+1234567890",
"transferPlan": {
"mode": "warm-transfer-say-message",
"message": "Incoming call from a customer asking about billing issues."
}
},
"content": "Please hold while I transfer you."
}'
```

**Provide an AI-generated summary:**

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
"type": "number",
"number": "+1234567890",
"transferPlan": {
"mode": "warm-transfer-say-summary"
}
},
"content": "Transferring you now."
}'
```

**Wait for operator to speak first:**

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
"type": "number",
"number": "+1234567890",
"transferPlan": {
"mode": "warm-transfer-wait-for-operator-to-speak-first-and-then-say-message",
"message": "Hi, I have a customer on the line who needs help with their order.",
"timeout": 30
}
},
"content": "Connecting you to our support team."
}'
```

**Use TwiML for custom announcements:**

```bash
curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control'
-H 'content-type: application/json'
--data-raw '{
"type": "transfer",
"destination": {
"type": "number",
"number": "+1234567890",
"transferPlan": {
"mode": "warm-transfer-twiml",
"twiml": "<Say voice=\"alice\" language=\"en-US\">Incoming transfer from support AI.</Say><Pause length=\"1\"/><Say>Customer issue: billing question.</Say>"
}
},
"content": "Please hold for transfer."
}'
```

<Note>
Warm transfer modes require Twilio, Vapi phone numbers, or SIP trunks. They do not support Telnyx or Vonage.
</Note>

**Available transfer plan modes:**
- `blind-transfer` - Immediate transfer (default)
- `blind-transfer-add-summary-to-sip-header` - Add summary to SIP headers
- `warm-transfer-say-message` - Say a custom message to the operator
- `warm-transfer-say-summary` - Say an AI-generated summary
- `warm-transfer-wait-for-operator-to-speak-first-and-then-say-message` - Wait for operator, then say message
- `warm-transfer-wait-for-operator-to-speak-first-and-then-say-summary` - Wait for operator, then say summary
- `warm-transfer-twiml` - Execute TwiML instructions
- `warm-transfer-experimental` - Use a transfer assistant for intelligent handoffs (see [Assistant-based warm transfer](/calls/assistant-based-warm-transfer))

### 6. Handoff Call
Handoff the call to a different assistant.

Expand Down
Loading