Server Messages
The messages Flux TTS sends back on /v2/speak — Connected, lifecycle and metadata events, interruption and configuration responses, warnings, errors, and the code reference.
The server replies to your Client Messages with JSON text frames interleaved with binary audio frames. This page documents every server-to-client message and the error/warning code reference.
Cadence at a glance: SpeechStarted marks the start of a turn and SpeechMetadata marks its end — every audio frame for a turn arrives between the two. Flush is your signal that all of the turn’s text has been sent; once it arrives, SpeechMetadata is our signal that all of the turn’s audio has been sent.
Connected
Sent immediately on a successful connection. Successor to v1/speak’s Metadata message.
SpeechStarted
Emitted at the start of each new turn, before audio streaming begins. Carries the server-assigned speech_id. Fires once per turn.
The speech_id is a server-minted identifier of the form dg_sp_<12 hex digits>. It is informational — useful for correlating logs.
When a turn becomes active. A Speak received while idle (the first Speak, or the first after a SpeechMetadata) starts a new active turn, and we emit SpeechStarted. There is only ever one active turn: a Speak received after you’ve Flushed the active turn but before its SpeechMetadata starts a pending turn. The active turn stays active until its SpeechMetadata — if you haven’t received SpeechMetadata, the turn is still being synthesized — at which point the next pending turn becomes active and gets its own SpeechStarted.
SpeechMetadata
Emitted once per turn, after we’ve sent all of the turn’s audio — our signal that synthesis for the turn is complete and no more audio is coming for it. It follows your Flush, which tells us no more text is coming for the turn. Reports billing and timing for the completed turn.
Per-turn vs. cumulative. Per-turn counts are reported here, once per turn (at Flush). Cumulative totals are reported once, at session end, in SessionMetadata as total_*.
SpeechInterrupted
Sent in response to an Interrupt. Reports exactly what the user heard and what they didn’t, plus a nested metadata block carrying the same shape as a standalone SpeechMetadata body.
One event per interrupted turn. On Interrupt, only SpeechInterrupted fires — the server does not also emit a standalone SpeechMetadata. Read SpeechMetadata.<field> for completed turns and SpeechInterrupted.metadata.<field> for interrupted ones. Feed text_spoken back into your LLM context so the next turn doesn’t repeat what the user already heard.
Flushed
Emitted when the turn’s buffer has actually been flushed after a manual Flush — not on receipt of the Flush, and it can be held back behind earlier pending turns. The turn’s SpeechMetadata follows.
SessionMetadata
Final server message before the WebSocket closes. Reports cumulative session totals — the sum across all turns.
An Interrupt rebases total_audio_duration_ms onto the audio the client actually played — audio generated past the interrupt point stops counting toward the session, so the total can decrease after a barge-in.
This is the one place cumulative totals are reported. Combined with the per-turn numbers in SpeechMetadata, you get clean reconciliation: per-turn for granular tracking, plus a final authoritative total.
ConfigureSuccess / ConfigureFailure
ConfigureSuccess
Sent when a Configure message is accepted. Echoes the applied configuration. Fires on receipt and validation, not on application — the change takes effect at the next segment boundary.
ConfigureFailure
Sent when a Configure message is rejected. The failing message has no effect — the prior configuration is retained and synthesis continues uninterrupted.
field and value identify the rejected field and the value you sent; they are present only when the failure is tied to a specific field/value. See the ConfigureFailure codes below.
Warning
Informational message; synthesis continues and the connection is unaffected. Every warning carries a code and a human-readable description.
See the warning codes below. Warnings are not rate-limited — every occurrence is emitted.
Error
A fatal, server-originated error. Unlike a Warning, an Error is always followed by a WebSocket close.
See the error codes below.
Warning codes
All warning codes follow Deepgram’s SCREAMING_SNAKE_CASE convention; the session stays open in every case.
Turn-scoped:
Inline controls and markup (inline pause and pronunciation controls are coming soon; their codes take effect when they ship):
Interrupt-scoped (in every case the Interrupt is ignored and no SpeechInterrupted is sent):
ConfigureFailure codes
Connection rejection codes
An invalid expressivity value rejects the connection with an HTTP 400 before the WebSocket upgrade completes — no Connected message is sent. See Expressivity.
Error codes
Every error is fatal and is followed by a WebSocket close frame. Codes use Deepgram’s DOMAIN-NNNN convention.
Related resources
- Client Messages — the messages these respond to
- The Speech Lifecycle — how these events sequence across a turn
- Cross-Turn Context — voice consistency across turns