Skip to main content
The handshake is paid once instead of per request, you push text while your LLM is still writing it, and you can cut a turn off the moment the user starts talking. Audio comes back base64-encoded inside JSON frames — the same PCM as HTTP.

Frames you send

object
required
First frame. Must carry "v2": true, and may set voice and language for the connection.
object
One sentence of a turn. Carries context_id and continue.
object
Drops a turn — queued and in-flight — and replies cancelled instead of end.
object
Keepalive. Answered with pong.

Frames you receive

object
Sample rate, channels, encoding, session id. Arrives after your start.
object
Base64 PCM, tagged with its context_id.
object
Exactly one per closed turn.
object
Sent instead of end when a turn was cancelled.
Send start first, then read metadata. The server does not speak until you do — waiting for metadata before sending start leaves both sides waiting forever.
"v2": true is required on the first frame. It selects the protocol for the whole connection and is latched on the first turn. Without it you get v1 frames — untyped audio, no context_id, no end — and your turn never terminates.