# Transfer to a Human

> Hand a live call to a person: a PSTN number (SIP REFER) or a human-agent queue. The same sid continues.

Escalate a live call to a person with `call.transfer(...)`. Pass `{ to }` to
forward the audio to a phone number over a SIP `REFER`. Or pass `{ agent }` to
re-attach the call to a different, human-backed agent in place. In both cases,
the original `sid` continues to address the call. Recordings, CDRs, and
analytics keyed on the `sid` stay intact.

Every snippet assumes a configured `Voice` client:

  
```ts
import { Voice } from "clutchcall_connect/voice";

const v = new Voice({
  baseUrl: "https://engine.firstbyte.fast",
  apiKey:  process.env.CLUTCHCALL_CREDENTIALS!,
  orgId:   "org_abc",
});
```
  
  
```python
import os
from clutchcall.voice import Voice

v = Voice(
    base_url="https://engine.firstbyte.fast",
    api_key=os.environ["CLUTCHCALL_CREDENTIALS"],
    org_id="org_abc",
)
```
  

## Forward the call to a person's phone

Transfer to an E.164 number. The SIP gateway issues a `REFER` toward the
target and emits a `transferred` lifecycle event. The same `sid` continues.

  
```ts
const call = await v.calls.get({ sid });
await call.transfer({ to: "+15557654321" });   // SIP REFER to a desk phone
```
  
  
```python
call = v.calls.get(sid=sid)
call.transfer(to="+15557654321")   # SIP REFER to a desk phone
```
  

> **TIP:**
> `call.transfer("+15557654321")` (a bare string) is shorthand for
> `{ to: "+15557654321" }` in the TypeScript SDK.

## Hand a bot call to a human queue

When an AI agent decides that it needs a person, re-attach the call to a
human-backed agent by id. The engine swaps the audio bridge to the new agent in
place, with no off-net forwarding. The caller's `sid` is preserved, so the
transcript and recording continue on one record.

  
```ts
// call started with agent: "triage-bot"; the bot asks to escalate
await call.transfer({ agent: "human-queue" });
```
  
  
```python
# call started with agent="triage-bot"; the bot asks to escalate
call.transfer(agent="human-queue")
```
  

The target `agent` routes into your ACD skill queue. The ACD offers the call to
the first available human agent, on a browser softphone or a registered SIP
phone. When the agent accepts, the engine bridges the agent to the caller.

## Full bot → human escalation

Originate with a triage bot. Then escalate on the bot's cue. First try an
in-platform human queue. If needed, fall back to forwarding to an on-call phone.

  
```ts
async function escalate(to: string) {
  // 1. start with an AI triage agent
  const call = await v.calls.originate({
    to, from: "+15558675309", trunkId: "trunk_main",
    agent: "triage-bot",
  });

  // 2. bot decides a human is needed → re-attach to the human queue
  await call.transfer({ agent: "human-queue" });

  // 3. or, forward the live audio to an on-call agent's phone
  // await call.transfer({ to: "+15557654321" });

  return call.sid;   // unchanged across the handoff
}
```
  
  
```python
def escalate(to: str) -> str:
    # 1. start with an AI triage agent
    call = v.calls.originate(
        to=to, from_="+15558675309", trunk_id="trunk_main",
        agent="triage-bot",
    )

    # 2. bot decides a human is needed → re-attach to the human queue
    call.transfer(agent="human-queue")

    # 3. or, forward the live audio to an on-call agent's phone
    # call.transfer(to="+15557654321")

    return call.sid   # unchanged across the handoff
```
  

> **NOTE:**
> Pass **exactly one** of `to` or `agent`. The Python SDK enforces the XOR and
> raises an error if you pass both or neither. The TypeScript SDK requires at
> least one.

> **NOTE:**
> Routing and accept are wired end-to-end. But the rich **warm-handoff context**
> is a product-level payload that you assemble in your app. This is the
> screen-pop of intent, qualification, and auth that the bot captured before the
> human hears audio. See
> [AI ↔ human handoff](/modalities/voice/transport-telephony/ai-human-handoff)
> for how the human agent subscribes to the live caller audio.

## Confirm the transfer landed

`transfer()` returns when the control plane accepts the request, not when the
target answers. Poll the call, or watch the `transferred` / `cleared`
lifecycle events, to see how the transfer resolved.

  
```ts
await call.transfer({ to: "+15557654321" });

const c = await v.calls.get({ sid });
console.log("post-transfer status:", c.status);
```
  
  
```python
call.transfer(to="+15557654321")

c = v.calls.get(sid=sid)
print("post-transfer status:", c.status)
```
  

## Related

  - **[AI ↔ human handoff](/modalities/voice/transport-telephony/ai-human-handoff)** — The full warm-handoff flow: mirroring caller audio to a human agent leg.
  - **[Handoffs](/modalities/voice/concepts/handoffs)** — How transfers, re-attach, and re-hosting fit the session model.
  - **[Call lifecycle](/modalities/voice/transport-telephony/call-lifecycle)** — The `transferred` event and the rest of the CTI stream.
  - **[Outbound call](/modalities/voice/cookbooks/outbound-call)** — Originate the call that you will transfer.
