Skip to main content
This page is the canonical reference for the Voice Agent WebSocket protocol: every event the client sends, every event the server emits, and the order they appear in. For the field-level schema of each event, see the Voice Agent WebSocket API reference and the Events reference.

Sequence diagram

Events at a glance

Client → server Server → client

Session initialization

Immediately after the WebSocket opens, send a session.update to configure the agent. You have two ways to configure:
  • Stored agent. Send { "agent_id": "<id>" } to bind to an agent created via the Agents REST API. The stored system_prompt, greeting, tools, input, and output are applied server-side.
  • Inline configuration. Omit agent_id and send system_prompt, greeting, tools, input, and output directly.
The two modes are mutually exclusive. See Deploy your agent and Session configuration for details.
The server responds with session.ready once the session is established:
Save session_id — you’ll need it to reconnect with session.resume if the WebSocket drops mid-conversation.

Sending audio

After session.ready, stream audio to the agent as input.audio events. Each event carries a base64-encoded chunk of PCM16 audio:
Send audio in chunks of roughly 50 ms. The default input format is mono 24 kHz PCM16; you can change encoding and sample rate through session.input.format. See Audio format for the full format specification and Encoding for supported encodings.
Do not send input.audio before session.ready. Audio sent before the session is established is discarded.

User turn

When turn detection decides the user has started speaking, the server emits input.speech.started. As speech continues, partial transcripts stream back as transcript.user.delta. When the user stops speaking, the server emits input.speech.stopped followed by a final transcript.user:
See Turn detection and interruptions for tuning turn detection.

Agent reply

Once the user turn ends, the agent generates a reply. Every reply is bracketed by reply.started and reply.done. In between, audio streams back as reply.audio events (base64 PCM16), and the full text arrives as transcript.agent after all audio has been delivered:
transcript.agent is emitted after the final reply.audio chunk, so it can be used to display the agent’s reply once playback completes.

Tool calls

If the agent decides to invoke a registered tool, the server emits a tool.call event. The current reply ends with reply.done, and the client is expected to run the tool and return the result via tool.result. A fresh reply.startedreply.done cycle follows once the tool result is received:
See Tool calling for the full tool-calling flow, including HTTP tools and client-side tools.

Updating configuration mid-session

You can send another session.update at any time to change mutable fields such as system_prompt, input.turn_detection, or output.volume. The server acknowledges with session.updated. Changing immutable fields (for example greeting, output.voice, or output.format) raises immutable_field. See Mutability after session.ready.

Session termination

To end a session cleanly, send session.end. The server flushes any in-flight events, emits session.ended, then closes the WebSocket with code 1000:
Always terminate sessions explicitly. Sessions that are not ended remain open and continue to accrue charges until the server auto-closes them.

Errors

If the session fails at any point, the server sends a session.error event and closes the connection:
See Troubleshooting for the full list of error codes and recovery guidance.