# Hand a live call to a person

Source: https://docs.usetone.ai/reference/calls/startTransfer

> Asks the agent on the call to transfer it to one of the destinations it may use, exactly as if it had decided to itself: the caller hears the transfer line, the person hears the brief, and every rule still applies — the destination must be verified, inside its hours and one of the agent's destinations, and a call makes at most two attempts.

`POST /v1/calls/{id}/transfer`
Asks the agent on the call to transfer it to one of the destinations it may use, exactly as if it had decided to itself: the caller hears the transfer line, the person hears the brief, and every rule still applies — the destination must be verified, inside its hours and one of the agent's destinations, and a call makes at most two attempts. A transfer that cannot start is `accepted: false` with a `refusal`, not an error. `409 call_not_live` when no agent is on the call. Send an `Idempotency-Key` to make a retry safe.

Requires the `write` scope.

## Parameters

| Name | In | | Meaning |
|---|---|---|---|
| `id` | path | required | The call's id. |

## Request body

| Field | Type | | Meaning |
|---|---|---|---|
| `destinationId` | string | required | The transfer destination (`GET /v1/transfer-destinations`). It must be verified, inside its hours, and one of the destinations the call's agent may transfer to — on a BYO call, which runs no agent, any of the org's. |
| `handoff` | string | optional | BYO calls only (an agent's call takes its agent's setting): `warm` keeps the caller with your bot until the person accepts, `cold` (the default) hands them over now. On the SIP gateway every transfer is warm. |
| `note` | string | optional | One short line for the person, quoted to them as "the agent noted". Never instructions. |
| `reason` | string | optional | Why the call is being handed over. The person hears it in the brief. Open set — handle an unrecognised value rather than throwing. Today: `caller_requested_human`, `out_of_scope`, `complaint`, `qualified_lead`, `repeated_failure`, `other`. |

### Example request

```json
{
  "destinationId": "9f1c2d84-4e3a-4f6c-b902-7d1e8a33c451",
  "handoff": "warm",
  "note": "Wants the premium plan, ready to pay today.",
  "reason": "qualified_lead"
}
```

## Response

| Field | Type | | Meaning |
|---|---|---|---|
| `accepted` | boolean | required | Whether a transfer started. The caller hears the agent's transfer line either way. |
| `refusal` | string | null | required | Why it did not start, when it did not. `in_progress`: a transfer is already under way. `not_available`: this call's agent cannot transfer (no transfer setting, or a carrier with no transfer path). The rest name the destination's state or a limit. Open set — handle an unrecognised value rather than throwing. Today: `not_available`, `unknown_destination`, `not_verified`, `disabled`, `outside_hours`, `attempts_exhausted`, `org_limit`, `carrier_busy`, `carrier_unavailable`, `in_progress`, `call_ended`. |
| `transfer` | object | null | required | The attempt, when one started — the same shape as `GET /v1/calls/{id}/transfers`. |

### Example response

```json
{
  "data": {
    "accepted": true,
    "refusal": null,
    "transfer": {
      "acceptedAt": null,
      "answeredAt": "2026-10-13T10:01:41Z",
      "attempt": 1,
      "bridgedAt": "2026-10-13T10:01:52Z",
      "brief": "Transfer from Acme's digital assistant, about a complaint. This call is recorded. Press 1 to take the call.",
      "destination": {
        "label": "Delivery team"
      },
      "endedAt": "2026-10-13T10:05:12Z",
      "hasRecording": true,
      "hasReturnRecording": false,
      "humanSeconds": 200,
      "id": "5b2c1e3d-9a4f-4e6b-8c7d-1f2e3a4b5c6d",
      "mode": "screened",
      "outcome": null,
      "reason": "out_of_scope",
      "requestedAt": "2026-10-13T10:01:30Z",
      "status": "bridged",
      "trigger": "model"
    }
  }
}
```
