Skip to main content
The Opal WebSocket Protocol uses Protocol Buffers for message encoding. All messages are wrapped in either ServiceBoundMessage (client to server) or ClientBoundMessage (server to client).
Messages are binary-encoded protobuf. JSON examples below are shown for readability. Download the proto file.
Need VAD-only without LLM inference? See the VAD WebSocket Protocol for a dedicated VAD API that streams voice activity events.

Connection

Authentication via Bearer token in the connection headers.

Client Messages

Messages sent from client to server, wrapped in ServiceBoundMessage.

InitializeSessionRequest

Must be the first message sent. Configures the session parameters.
Reconfigure an ongoing session. Useful for changing audio input settings or the system prompt on the fly. You can update either field or both.
Reconfiguration may not be seamless. There may be glitches or dropped audio during the transition.
User input data (audio or text).
Define or update available tools. Replaces all existing definitions.Each ToolDefinition contains:
Response to a tool call request from the server.
Every ToolCallRequest must receive a corresponding ToolCallResponse, even if execution fails.
Manually trigger inference processing immediately, instead of waiting for natural pauses or end-of-input signals.
Primary use case is generating an initial greeting. Model behavior may be unpredictable if used directly after a model response.
Use flush_vad to commit speech the VAD has not released yet, when the trigger comes from an external signal such as a push-to-talk button or a wake word rather than from natural end-of-speech detection. It is a no-op when the buffer is empty.
Request the full conversation history. The server responds with a ChatHistory message.
Reports how many audio bytes the client has played for a given turn.The server uses this to truncate the LLM context to exactly what the caller heard when they interrupt, and to pace ModelSpeechProgress. Without these reports it falls back to a server-side elapsed-time estimate.
Omitting turn_id is not the same as sending 0. Turn IDs are 0-based, so a report without one is read as coming from a client written before turn correlation existed, and the server applies it to the current response instead of the turn you meant.
Set supports_playback_reporting in InitializeSessionRequest when you intend to send these reports.
Instructs the service to speak the given text via TTS immediately, bypassing the LLM. Any active inference is cancelled and the audio buffer is cleared before the text is spoken.Use uninterruptable for compliance announcements, such as notifying the caller that they are speaking with an AI.
Liveness check. The server replies with Pong. Carries no fields.Use it to keep a session alive when nothing else is being sent, or to measure round-trip latency.
Runs a one-shot LLM inference over the current conversation history without modifying it. Useful for side tasks like summarization or classification. The server responds with a ConversationQueryResult.At least one of prompt or instructions must be provided.

Server Messages

Messages sent from server to client, wrapped in ClientBoundMessage. Most of these messages carry a turn_id identifying the assistant turn they belong to. Turn IDs are 0-based, so 0 is a real turn rather than a missing value. ResponseBegin, ResponseEnd, ModelSpeechProgress and InferenceComplete always carry one, whereas ModelTextFragment and ModelAudioChunk carry an optional turn_id. When absent, the message belongs to the current turn. An assistant turn ends in three stages, each reported by a different message. They are not interchangeable.

SessionReady

Sent once the session is fully initialized and ready to accept input, after TTS warmup completes. Wait for this message before sending UserInput. Carries no fields.
Streamed text output as tokens arrive.ModelTextFragment is emitted for every assistant turn, whether or not TTS is configured, and carries text as the model generates it.When TTS is configured, these fragments run ahead of speech synthesis, so they reflect what the model has produced rather than what the caller has heard. ModelSpeechProgress reports the playback-paced view of the same text.
TTS audio output when a TTS provider is configured.ModelAudioChunk carries audio only. For the text that goes with it, use ModelSpeechProgress.
Reports how much of an assistant turn’s text has become audible. Emitted continuously while TTS audio is playing.Where ModelTextFragment gives you the text as the model produces it, ModelSpeechProgress gives you the same text paced to playback. Use it to display what the caller has actually heard.Concatenating text in arrival order reproduces the same text as the turn’s ModelTextFragment messages, so the result is always a valid prefix of the generated text.
Treat exact as debug information only, never as a correctness gate.A segment with exact: false still contains the correct and complete text. It may just not correspond precisely to the audio played so far. The server keeps this drift as small as it can, but a small amount is unavoidable.
The server derives audio_bytes_played from its own estimate of playback. Send PlaybackPositionReport messages to replace that estimate with your client’s real position and tighten the whole stream.
Model requests to execute a tool.
Notification to clear the audio playback buffer. Sent proactively when the user starts speaking, regardless of whether there is ongoing TTS playback.When received, immediately discard any buffered audio that hasn’t been played yet. This message may be sent multiple times if the user interrupts multiple times.
Notification that the model has begun its response.
The LLM has finished producing this turn’s output.Generation is done, but the turn is not. TTS audio may still be synthesizing, and further events for the turn will still arrive.
Notification that no more audio is coming for this turn. Sent once all audio packets for the turn have been sent.
ResponseEnd does not mean the turn is finished. The turn’s content can still change afterwards, for example when an interruption shortens it.
The server’s authoritative view of one turn’s content at a point in time.
Snapshots are not guaranteed to be monotonic. A turn can produce several of them, and content can be rolled back, for example when an interruption means part of a response was never heard.
is_final means the turn’s content will not change again. It does not mean the turn stays visible forever since context truncation can still remove it from the model’s context later, which ContextTruncated reports.
The full conversation history, returned in response to ExportChatHistoryRequest.
Messages were removed from the LLM’s context window to fit the token budget.Only turns newly truncated in this inference cycle are listed. Turns reported in an earlier ContextTruncated are not repeated.A truncated turn keeps its content and stays in an exported ChatHistory. It is the model’s view that shrinks, not yours. The turn’s ChatMessage.truncated_at_response_turn_id records the same relationship, so you can look up when it happened after the fact.
Emitted on every VAD state-machine transition. Always sent, regardless of whether enable_vad_frame_telemetry is set.
Per-frame VAD telemetry, emitted at ~50 Hz (20 ms frames on 16 kHz audio). Only sent when enable_vad_frame_telemetry: true was set in InitializeSessionRequest.
This message type is experimental and may be changed or removed without a major version bump. It is intended for debugging and telemetry. Do not rely on it for critical functionality.
Reply to a client Ping. Carries no fields.
Structured error notification sent before the server closes the connection.
Async transcription result for a completed user audio turn. Sent after the transcription worker finishes processing.
Result of a ConversationQuery request.

Type Definitions

AudioLineConfiguration

SampleFormat

VadConfiguration

Voice Activity Detection settings.

InferenceConfiguration

TtsConfiguration

Optional text-to-speech configuration. If omitted, raw text fragments are sent.

ElevenLabsVoiceSettings

Fine-tuning settings for ElevenLabs voices.

ElevenLabsLocation

Controls which ElevenLabs regional endpoint is used. See ElevenLabs data residency docs for details.

HostedVoiceRef

Reference a Deepslate-hosted voice that is already available on the server.

HostedVoiceCloneV1

Provide an inline custom voice clone for hosted TTS using reference audio and its exact transcript.

HostedTtsMode

Controls the quality/latency trade-off for hosted TTS generation.

VadState

State of the VAD debounce machine. For the full state machine, including the debounce windows and the threshold rule, see VAD.

Duration

InferenceTriggerMode

Controls how this input interacts with ongoing inference.

TextData

Text input wrapper.

ChatMessage

A single message in the conversation history.

ChatMessageRole

ChatDeliveryStatus

ChatMessageContent

A single content block within a chat message. Contains one of:

ChatTextContent

Text content from a conversation turn, with optional TTS audio. When TTS is active, each synthesized sentence becomes a ChatTextContent with both fields populated.

ChatAudioData

Self-describing audio data including format metadata so consumers can decode without out-of-band knowledge.
If you reconfigure the audio pipeline mid-conversation, the format may change. Always inspect the format field rather than assuming it matches the initial configuration.

SessionErrorCategory

Broad error categories for programmatic handling of SessionErrorNotification.