Coming from the OpenAI Realtime API? The wire format is intentionally similar. See Migrate from the OpenAI Realtime API for an event-by-event mapping and the behavioral differences.
How a conversation flows
- Open a WebSocket connection, optionally setting the audio format through query parameters.
- Telnyx authenticates the connection, starts a conversation with the requested assistant, and sends a
session.createdframe confirming the negotiated input and output audio formats. - Stream microphone audio as
input_audio_buffer.appendframes. - Telnyx runs server-side voice-activity detection (VAD) and sends
input_audio_buffer.speech_startedandinput_audio_buffer.speech_stoppedon speech edges, followed by the user’s transcript. - The assistant responds with a
response.createdframe, a stream of audio and transcript deltas, thenresponse.output_audio.doneandresponse.done. - Speaking while the assistant is talking triggers barge-in: Telnyx stops the response and starts a new turn.
Connect and authenticate
Authorization header:
Browsers cannot set headers on WebSocket connections, so connect from your backend. For browser-based voice agents, use the WebRTC-based
@telnyx/ai-agent-lib library instead — it handles media capture, playback, and client-side tools for you.type field. Audio travels inside JSON frames as base64 — never as binary WebSocket frames.
Session lifecycle
The first frame Telnyx sends issession.created. It confirms the conversation has started and reports the negotiated audio formats — read the output rate from it before playing any assistant audio:
server_vad — there is no manual turn mode to configure.
Handling audio
Stream microphone audio
Send audio asinput_audio_buffer.append frames. The audio field is base64-encoded, raw little-endian PCM16 (16-bit signed, mono) at the sample rate you chose with input_sample_rate:
- Stream at a real-time pace, in small chunks (for example 20–100 ms of audio per frame). The server enforces an ingress budget; sending far faster than real time fails with an
ingress_budget_exceedederror. - Keep frames under 1 MiB. Larger frames are rejected with a
frame_too_largeerror. - Wait for
session.createdbefore sending audio.
Speech detection and user transcripts
Telnyx runs voice-activity detection server-side and reports speech edges. Both events are edge-triggered — each is sent only when the speaking state actually changes, andspeech_stopped is never sent without a preceding speech_started:
Receive assistant audio
Each assistant turn arrives as an ordered sequence of frames, correlated byresponse_id:
response.done. Buffer the decoded PCM16 in a queue that your audio output drains at the output sample rate.
Interruption and barge-in
Barge-in is built in. If the user speaks while the assistant is talking, Telnyx detects it, stops generating the response, and starts a new turn — you don’t send anything to make that happen. The interrupted turn finishes withresponse.done and status: "cancelled".
One thing remains your responsibility: audio you have already received and queued locally. When you see input_audio_buffer.speech_started during playback, flush your local playback queue so the assistant doesn’t keep talking out of your speakers over the user:
response.cancel:
response_id to target a specific response, or omit it to cancel the current one. Cancelling flushes playback on the Telnyx side and is followed by a response.done frame with status cancelled. Cancelling a stale or already-finished response is a no-op.
Interruption sensitivity is tuned on the assistant, not the socket — see Interruption Settings.
Send text instead of audio
Inject a completed user turn as text withconversation.item.create. The assistant answers it exactly as it would a spoken turn — including responding with audio:
response.create frame — the assistant owns turn-taking and answers automatically. Items of any other shape are rejected with an invalid_item error.
Tool calls
Assistants can use two kinds of tools during a realtime conversation. Both are configured on the assistant — see the Tools Library.Server-side tools: observe
Webhook and MCP tools execute on Telnyx. The socket surfaces them as informational frames so you can show tool activity in your UI, but you don’t execute or respond to them:Client-side tools: execute and respond
When the assistant invokes a client-side tool, Telnyx sends aconversation.item.created frame containing a function_call item. Run the tool locally, then return the result with a conversation.item.create frame carrying a function_call_output item that references the same call_id. The assistant continues once the result arrives, or after the tool times out.
Error handling
Errors arrive aserror frames. Some errors are non-fatal and leave the session open; others close the connection after the frame is sent.
If the connection closes, reconnecting starts a new conversation — a fresh
conversation_id is issued in session.created.
Learn more
- Migrate from the OpenAI Realtime API — Event-by-event mapping and behavioral differences
- Conversation WebSocket reference — The full frame-by-frame reference, under Assistants API → Conversation WebSocket in the sidebar
- Client-Side Tools — Configure tools that execute in your application
- Transcription Settings and Interruption Settings — Tune how the assistant hears and yields
- Voice Assistant Quickstart — Create and configure an assistant in the Portal