Server Messages

The messages Flux TTS sends back on /v2/speak at Early Access — Connected, lifecycle and metadata events, 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.

Early Access surface. At EA the server emits the events below. Interruption reporting (SpeechInterrupted) and configuration responses (ConfigureSuccess / ConfigureFailure) are planned for GA alongside Interrupt and Configure.

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.

1{
2 "type": "Connected",
3 "request_id": "550e8400-e29b-41d4-a716-446655440000",
4 "model_name": "flux-alexis-en",
5 "model_version": "2026.06.01",
6 "model_uuids": ["b3e47c20-9f81-4a2e-bd15-8d7c6e2a1f09"]
7}
FieldTypeDescription
request_idstring (UUID)ID of the /v2/speak request.
model_namestringResolved model name (e.g. flux-alexis-en).
model_versionstringResolved model version.
model_uuidsarray of string (UUID)Resolved model UUIDs. A list, because a resolved model may be backed by more than one underlying model.

SpeechStarted

Emitted at the start of each new turn, before audio streaming begins. Carries the server-assigned speech_id. Fires once per turn.

1{
2 "type": "SpeechStarted",
3 "speech_id": "dg_sp_a1b2c3d4e5f6"
4}

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.

1{
2 "type": "SpeechMetadata",
3 "speech_id": "dg_sp_a1b2c3d4e5f6",
4 "audio_duration_ms": 3200,
5 "input_character_count": 47,
6 "billable_character_count": 47,
7 "controls_applied": {
8 "pronunciations_applied": 0,
9 "pronunciation_warnings": 0
10 }
11}
FieldTypeDescription
speech_idstringServer-assigned turn identifier. Informational.
audio_duration_msintegerTotal audio duration produced for this turn, in milliseconds.
input_character_countintegerRaw input character count for this turn, before text normalization.
billable_character_countintegerBillable character count for this turn — the input minus stripped inline-control characters; always ≤ input_character_count.
controls_appliedobjectControls applied during the turn. At Early Access it always reports pronunciations_applied and pronunciation_warnings, both 0 — these tallies populate at GA.

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_*.

Flushed

Emitted when the turn’s buffer has actually been flushed after a manual Flushnot on receipt of the Flush, and it can be held back behind earlier pending turns. The turn’s SpeechMetadata follows.

1{
2 "type": "Flushed",
3 "speech_id": "dg_sp_a1b2c3d4e5f6"
4}

SessionMetadata

Final server message before the WebSocket closes. Reports cumulative session totals — the sum across all turns.

1{
2 "type": "SessionMetadata",
3 "total_audio_duration_ms": 184500,
4 "total_input_character_count": 4280,
5 "total_billable_character_count": 4280
6}

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.

Warning

Informational message; synthesis continues and the connection is unaffected. Every warning carries a code and a human-readable description.

1{
2 "type": "Warning",
3 "code": "NO_ACTIVE_SPEECH",
4 "description": "There is no active turn. The request will be ignored."
5}

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.

1{
2 "type": "Error",
3 "code": "MESSAGE-0000",
4 "description": "The message could not be parsed."
5}

See the error codes below.

Warning codes

All warning codes follow Deepgram’s SCREAMING_SNAKE_CASE convention; the session stays open in every case.

CodeTrigger
NO_ACTIVE_SPEECHA speech-scoped message (e.g. Flush) was received with no active turn. No-op.
SYNTHESIS_RETRYINGA synthesis request to the model failed and is being retried. The session continues; a fatal Error is sent only if retries are exhausted.

Additional warning codes (pronunciation and inline-control validation, markup stripping) are planned for GA with the features that emit them.

Error codes

Every error is fatal and is followed by a WebSocket close frame. Codes use Deepgram’s DOMAIN-NNNN convention.

CodeErrorTrigger
MESSAGE-0000Unparseable client messageA client message could not be parsed.
DATA-0000Invalid commandA message contained an invalid command.
BIG-0000Message too largeA message was too large to process.
NET-0000Internal server errorThe server hit an unexpected condition.
NET-0001Failed to receive messageThe server failed to receive a message.
NET-0002Failed to send messageThe server failed to send a message. In practice you won’t observe this — if the server can’t send messages, it can’t deliver this error either.
NET-0003Time limit exceededThe session time limit (1 hour) was exceeded.
NET-0004Inactive clientNo client message arrived within the 60s inactivity window; the session was closed. Send a WebSocket Ping or Pong to keep an idle session alive.