> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Warm Transfer Acceptance

> Let the transfer destination talk to your Voice AI Assistant and accept or decline the call before the caller is bridged.

A warm transfer normally plays a recorded handoff message to the destination and then bridges the calls, whether or not the destination is ready to take them. Warm transfer acceptance adds a live consult step: once the destination answers, the assistant speaks with them privately, delivers the handoff context, and asks whether they accept the call. Only an explicit acceptance bridges the caller.

While the consult happens, the caller stays with the assistant and keeps hearing ringback — they never hear the exchange.

***

## How it works

1. The assistant calls the transfer tool and Telnyx dials the selected target.
2. The destination answers. Instead of playing recorded audio, the assistant joins the destination on a private leg.
3. The assistant delivers the warm transfer message and asks whether they take the call.
4. The assistant finalizes the transfer with the built-in `complete_transfer` tool:
   * **Accept** — the caller and the destination are bridged and the assistant leaves the call.
   * **Decline** — the destination leg is hung up and the assistant returns to the caller with the reason the destination gave.
5. If the destination hangs up, or nobody decides within two minutes, the destination leg is dropped and the assistant returns to the caller.

The `complete_transfer` tool is added to the assistant automatically when acceptance is enabled — you do not configure it. If your assistant already has a tool named `complete_transfer`, acceptance is disabled on that assistant to avoid a name collision, so pick a different name for your own tool.

***

## Configuration options

Acceptance is configured inside the transfer tool, under `warm_transfer_acceptance`:

| Field                          | Type                  | Default   | Description                                                               |
| ------------------------------ | --------------------- | --------- | ------------------------------------------------------------------------- |
| `enabled`                      | boolean               | `false`   | Whether the destination must accept before the calls are bridged.         |
| `end_user_target_context_mode` | `private` \| `shared` | `private` | Whether the consult with the destination is kept out of the conversation. |

### Context modes

The consult is a real conversation between your assistant and the destination, so you choose whether it becomes part of the conversation record:

| Mode      | Behavior                                                                                                                                                                                                                                                                                       |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `private` | The exchange never reaches the conversation history, AI Conversations, webhooks or insights. The caller-facing turn only sees the transfer tool result, rewritten with the outcome — including the reason on a decline. Use this when the handoff may contain notes the caller should not see. |
| `shared`  | The exchange stays in the conversation like any other messages, and is available in history, webhooks and insights.                                                                                                                                                                            |

### Requirements

* **A warm message must always be available.** Set `warm_transfer_instructions` on the transfer tool, or a `message` on every target. Saving an assistant with acceptance enabled and neither of these returns a validation error. When both are present, the target's `message` wins.
* **Only for `ai_assistant_start` conversations.** Acceptance does not apply to `gather_using_ai`, Conversation Relay, or web calls.
* **Single-caller conversations only.** If the conversation is in a conference or has more than one invited user participant, the transfer falls back to a regular warm transfer with recorded playback.

If the consult cannot be set up for any reason, the transfer degrades gracefully: the warm transfer message is played to the destination as audio and the calls are bridged, exactly as a warm transfer without acceptance.

***

## Setting up via API

Configure `warm_transfer_acceptance` within the transfer tool when creating or updating an assistant.

### Ask the destination to accept

```bash theme={null}
curl -L 'https://api.telnyx.com/v2/ai/assistants' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer <TOKEN>' \
  --data-raw '{
    "name": "Support Agent",
    "instructions": "You are a support agent. Transfer calls to the support team when the caller asks for a human.",
    "model": "moonshotai/Kimi-K2.5",
    "tools": [
      {
        "type": "transfer",
        "transfer": {
          "targets": [
            {
              "name": "Support Team",
              "to": "+15551234567"
            }
          ],
          "from": "+15553456789",
          "warm_transfer_instructions": "Briefly summarize why the caller is being transferred and what they already tried. Then ask whether they can take the call.",
          "warm_transfer_acceptance": {
            "enabled": true
          }
        }
      }
    ]
  }'
```

### Share the consult with the conversation record

Set `end_user_target_context_mode` to `shared` when you want the exchange with the destination stored alongside the rest of the conversation:

```bash theme={null}
curl -L 'https://api.telnyx.com/v2/ai/assistants' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer <TOKEN>' \
  --data-raw '{
    "name": "Support Agent",
    "instructions": "You are a support agent. Transfer calls to the support team when the caller asks for a human.",
    "model": "moonshotai/Kimi-K2.5",
    "tools": [
      {
        "type": "transfer",
        "transfer": {
          "targets": [
            {
              "name": "Support Team",
              "to": "+15551234567"
            }
          ],
          "from": "+15553456789",
          "warm_transfer_instructions": "Briefly summarize why the caller is being transferred and what they already tried. Then ask whether they can take the call.",
          "warm_transfer_acceptance": {
            "enabled": true,
            "end_user_target_context_mode": "shared"
          }
        }
      }
    ]
  }'
```

### Give each target its own handoff message

A `message` on a target replaces the message the assistant would compose from `warm_transfer_instructions`, and satisfies the warm-message requirement on its own:

```bash theme={null}
curl -L 'https://api.telnyx.com/v2/ai/assistants' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer <TOKEN>' \
  --data-raw '{
    "name": "Support Agent",
    "instructions": "You are a support agent. Route callers to the right team.",
    "model": "moonshotai/Kimi-K2.5",
    "tools": [
      {
        "type": "transfer",
        "transfer": {
          "targets": [
            {
              "name": "Billing",
              "to": "+15551234567",
              "message": "I have a caller with a billing question. Can you take it?"
            },
            {
              "name": "Technical Support",
              "to": "+15557654321",
              "message": "I have a caller with a device issue that I could not resolve. Can you take it?"
            }
          ],
          "from": "+15553456789",
          "warm_transfer_acceptance": {
            "enabled": true
          }
        }
      }
    ]
  }'
```

***

## Combining with voicemail detection

Acceptance works alongside [voicemail detection on transfer](/docs/inference/ai-assistants/voicemail-detection-on-transfer). When AMD is enabled on the transfer, the consult starts once the destination is identified as a human. If voicemail is detected, the configured voicemail action runs instead — both `stop_transfer` and `leave_message_and_stop_transfer` end the transfer, so no consult takes place and the assistant returns to the caller.

***

## Related resources

* [Voice AI Assistant API Reference](/api-reference/assistants/create-an-assistant#transfertool) - Complete transfer tool API documentation, including the `warm_transfer_acceptance` parameters.
* [Voicemail Detection on Transfer](/docs/inference/ai-assistants/voicemail-detection-on-transfer) - Detect voicemail on the transfer destination and respond automatically.
* [Agent Handoff](/docs/inference/ai-assistants/agent-handoff) - Hand a conversation from one assistant to another instead of to a human.
* [Attach an AI Assistant to a Call](/docs/voice/programmable-voice/ai-assistant-start) - Start an assistant on a live call with `ai_assistant_start`.
