# Transfer to a person

Bring a person onto a phone call that is already happening, for example when the caller asks for a human. This works for [calls that you make](https://getstream.io/agents/docs/python/telephony/making-calls/) and [calls that you accept](https://getstream.io/agents/docs/python/telephony/accepting-calls/).

The agent can do it by itself when the caller asks, or your backend can do it when your code decides.

## Let the agent transfer

Only the agent hears the caller ask for a person, so the agent acts. It gets a `transfer` tool, rings the person and leaves the call.

### Give the session a number

The agent gets the `transfer` tool only when its session acts from one of your numbers. The person sees that number calling.

With the CLI, set `phone` when you create the session:

```sh
curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
getstream agents api CreateSession --request '{
  "agent": "my-agent",
  "id": "'"$SESSION_ID"'",
  "start_voice": true,
  "navigating": true,
  "phone": {"number": "+15125550100"}
}'
```

In Python, set `phone` in `SessionOptions`. The other SDKs set it for you when they place or answer a call.

```python
from vision_agents.plugins import stream
from vision_agents.plugins.stream import SessionOptions

agent = stream.Client().agent("my-agent")

session = await agent.sessions.create(
    SessionOptions(
        start_voice=True,
        navigating=True,
        phone=stream.SessionPhone(number="+15125550100"),
    )
)
```

For a call you place, use the number you call from. For a call you accept, use the number the caller rang (`call.called_number` in Python), leave out `navigating`, and set `id` to the session id of the call, as in [Answer from your code](https://getstream.io/agents/docs/python/telephony/accepting-calls/#answer-from-your-code).

### Tell the agent who to transfer to

The agent only knows the numbers that you give it, so put the number to transfer to in `instructions.md`:

```md title="agents/my-agent/instructions.md"
When the caller asks for a person, call transfer with to +15125550199 and a one-sentence summary
of who is calling and what they want. Say goodbye in the same reply.
```

If you use a guardrail, allow requests to speak to a person. Otherwise the guardrail refuses "Can I talk to a person?" before the agent can act.

### With or without a summary

With a summary, the agent waits for the person to answer, up to 45 seconds. Then it says the summary and leaves. The caller hears the summary too. If nobody answers in time, the agent leaves without saying it.

Without a summary, the agent leaves right after it dials the person, before they answer.

The agent decides whether to give a summary. To steer it, say so in `instructions.md`, as above.

### What happens after the agent transfers

Stream rings the person from the session's number. The person sees that number, not the caller's.

Your code gets a `transferred` event, then a `left` event when the agent leaves. Close the session then. The caller stays on the call. If the person does not answer, the caller is left alone on it.

If the transfer fails, the agent is told why. It stays on the call and tells the caller.

## Transfer from your backend

Use this when your code decides who takes over, for example from a tool that you registered. Send the number to call from, the person's number, and the `session_id`: the `id` that you gave `CreateSession`, or the id of the session your SDK opened. The person joins that session's Stream call.

### With the CLI

```sh
getstream agents api TransferPhoneCall --request '{
  "from": "+15125550100",
  "to": "+15125550199",
  "session_id": "'"$SESSION_ID"'"
}'
```

### With an SDK

```ts label="JavaScript"
await agent.client.post("/v1/phone/calls/transfer", {
  body: {
    from: "+15125550100",
    to: "+15125550199",
    session_id: "9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44",
  },
});
```

```python label="Python"
from vision_agents.plugins import stream

await stream.Phone().transfer(
    from_="+15125550100",
    to="+15125550199",
    session_id="9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44",
)
```

```ruby label="Ruby"
agent.client.post("/v1/phone/calls/transfer", body: {
  from: "+15125550100", to: "+15125550199", session_id: "9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44"
})
```

```php label="PHP"
$agent->client->post('/v1/phone/calls/transfer', body: [
    'from' => '+15125550100',
    'to' => '+15125550199',
    'session_id' => '9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44',
]);
```

```go label="Go"
client, err := agent.Client()
if err != nil {
	return err
}

transferred, err := client.TransferPhoneCallWithResponse(ctx, acceleration.TransferCallRequest{
	From: "+15125550100", To: "+15125550199", SessionId: "9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44",
})
if err != nil {
	return err
}
if transferred.JSON202 == nil {
	return fmt.Errorf("transferring the call: %s", transferred.Status())
}
```

```csharp label="C#"
using System.Text.Json;

await agent.Client.PostAsync<JsonElement>("/v1/phone/calls/transfer", new
{
    from = "+15125550100",
    to = "+15125550199",
    session_id = "9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44",
});
```

```rust label="Rust"
use vision_agents::types::TransferCallRequest;

let client = agent.router()?;
client
    .transfer_phone_call(&TransferCallRequest {
        from: "+15125550100".into(),
        to: "+15125550199".into(),
        session_id: "9b2f6c1e-4d7a-4e3b-8a51-2c0f7d9e1a44".into(),
        ..Default::default()
    })
    .await?;
```

The response comes at once, with the vendor's status, such as `queued`.

### What happens after your backend transfers

A transfer adds a second phone call. The caller stays where they are.
Stream rings the person from the `from` number, and the person sees that number. When the person answers, they join the same Stream call.

The agent stays in the call and keeps talking. Close the session once the person has joined, which you see as a second `participant_joined` event. The caller and the person stay on the call.

The number that you call from is one of your Stream numbers, or a number on [your SIP trunk](https://getstream.io/agents/docs/python/telephony/sip-trunk/).
For a number on your SIP trunk, the call goes out through your carrier.

---

For the most recent version of this documentation, visit [https://getstream.io/agents/docs/python/telephony/transfer/](https://getstream.io/agents/docs/python/telephony/transfer/).