Call Commands

View as Markdown

Call commands are sent over the per-call media connection associated with an ActiveCall. The control connection delivers events and manages connection health, but it does not carry answer(), connect(), close(), or disconnect().

answer()

Answers an incoming call and establishes the audio stream between your server and the caller.

1await call.answer()

After answering, the call enters the ANSWERED state. Your server is now responsible for audio:

  • Use call.audio_stream() to receive the caller’s audio
  • Use call.send_audio() to play audio back to the caller
  • If you don’t send any audio, the caller hears silence

connect(ring_time_seconds=60)

Connects the call to the original callee (the SIM card or called number associated with the connector). This initiates a 3-way conference between the caller, the callee, and your agent.

Parameters:

  • ring_time_seconds (optional, default: 60) - How long to ring the callee before giving up.
1await call.connect()

After a successful connect, the call enters the CONNECTED state. Your agent stays in the call and can:

  • Listen to the conversation
  • Send audio to the conference
  • Switch between barge(), whisper(), and spy() modes
  • Leave the conference with close()

Note: The destination cannot be changed. connect() always routes to the original callee (SIM or called number). To route calls to alternate destinations, Transfer and Forward commands will be available in a future release.

whisper()

Switches the agent’s audio mode so that only the callee (the connected third party) can hear the agent. The caller cannot hear the agent’s audio.

1await call.connect()
2await call.whisper()
3await call.send_audio(private_guidance_audio)

barge()

Switches the agent’s audio mode so that both the caller and callee can hear the agent. This is the default mode after connect().

1await call.barge()
2await call.send_audio(announcement_audio)

spy()

Switches the agent to listen-only mode. Neither the caller nor the callee can hear the agent, but the agent can still receive audio from the call.

1await call.spy()
2async for chunk in call.audio_stream():
3 await analyze_audio(chunk)

close()

Closes the call and releases SDK resources. The behavior depends on the current call state:

  • After connect(), the agent leaves the call while the caller and callee remain connected to each other
  • After answer() without connect(), the call ends for both the agent and the caller

Raises WSSCallError if the close command fails.

1await call.close()

disconnect()

Ends the call for all parties. Use this when your application wants the server to terminate the conversation entirely.

1await call.disconnect()

Common Call Flows

These patterns combine the commands above into typical real-world scenarios.

1. Basic AI Agent (Answer and Talk)

The simplest flow: answer the call and let the AI handle the conversation.

1@client.on(events.INCOMING_CALL)
2async def handle_call(call: ActiveCall):
3 await call.answer()
4
5 async for chunk in call.audio_stream():
6 response = await ai_model.generate(chunk)
7 await call.send_audio(response)
8
9 await call.close()

State flow: PENDING -> ANSWERED -> DISCONNECTED

2. AI Front-desk (Answer, Gather Info, Connect and Leave)

The agent answers to greet or authenticate the caller, then connects to the original callee and leaves the call.

1@client.on(events.INCOMING_CALL)
2async def front_desk_flow(call: ActiveCall):
3 await call.answer()
4
5 # AI gathers information, verifies identity, etc.
6 # ...
7
8 # Connect to the original callee, then leave the conference
9 await call.connect()
10 await call.close()

State flow: PENDING -> ANSWERED -> CONNECTED -> DISCONNECTED

3. AI Assistant (Connect and Whisper)

The agent connects the caller to the callee and privately coaches one side.

1@client.on(events.INCOMING_CALL)
2async def assistant_flow(call: ActiveCall):
3 await call.answer()
4
5 # Connect the caller to the original callee
6 await call.connect()
7
8 # Switch to whisper mode to privately guide the callee
9 await call.whisper()
10 await call.send_audio(private_guidance_pcm)

State flow: PENDING -> ANSWERED -> CONNECTED

4. Direct Routing (Connect Without Answering)

Route the call to the original callee without your agent answering first. The caller stays on ringing.

1@client.on(events.INCOMING_CALL)
2async def route_call(call: ActiveCall):
3 await call.connect()

State flow: PENDING -> CONNECTED

5. End the Call for Everyone

Use disconnect() when your application needs to terminate the conversation instead of just leaving it.

1@client.on(events.INCOMING_CALL)
2async def route_or_end(call: ActiveCall):
3 await call.answer()
4 await call.send_audio(await tts.synthesize("Goodbye."))
5 await call.disconnect()

Next Steps