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 and calls that you accept.

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:

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.

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.

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:

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

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

With an SDK

from vision_agents.plugins import stream

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

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. For a number on your SIP trunk, the call goes out through your carrier.