Skip to main content
The WebSocket API streams speech in real time over a single persistent connection. Unlike the HTTP endpoints, you can send text incrementally, as it is produced by an LLM or typed by a user, and receive audio as it is synthesized. This is the lowest-latency option and the right choice for voice agents and long-form speech.
Building a voice agent that must stop speech when the user interrupts? The multi-context WebSocket (beta) lets you cancel a reply and start the next one without reconnecting.

Endpoint

For the full message schemas and an interactive connection playground, see the TTS WebSocket reference. To measure first-audio latency on fresh and reused sessions, use the latency testing tool.

Authenticating

The WebSocket accepts your API key either as a header or as a query parameter (useful for browser clients that cannot set headers on a WebSocket handshake):
Prefer the chariotai-api-key header where your client allows it. If authentication fails, the server accepts the socket, sends an error frame, and closes with code 1008.

How a session works

The server buffers the text you send and does not synthesize it until you ask it to:
1

Send text

Send one or more input.text messages. Text accumulates in the server’s buffer. Nothing is generated yet.
2

Flush to generate

Send input.flush. The server synthesizes everything buffered so far and streams the audio back. The session stays open, so you can send more text and flush again.
3

Finish

Send input.done when no more text is coming. The server flushes any remainder and ends the session.
Flushing is what triggers generation. Send input.text as often as you like as fragments arrive, then input.flush at the point you want audio for. Flushing at natural boundaries, such as the end of a sentence or clause, gives the most natural speech.

Connection parameters

Pass these as query parameters on the connection URL:
string
required
UUID of the voice to synthesize with.
string
default:"chariot-v0"
Use chariot-v0 or chariot-multilingual-v1. The selected voice must support the model. Fixed for the session. See Models.
number
default:"1.0"
Choose a value from the selected model’s speeds list for your voice. Chariot v0 supports only 1.0. Fixed for the session.
integer
default:"0"
An integer from 0 to 4. Higher values trade quality passes for lower latency. Applies to the whole session.
string
default:"pcm"
Audio encoding of the binary frames. One of pcm (raw signed 16-bit LE PCM) or wav (streaming WAV, a RIFF header followed by PCM).
number
default:"60"
Seconds the server waits for a client message before closing the session as idle. Must be greater than 0 and at most 300.
boolean
default:"false"
Controls whether Chariot stores the generated audio. When false, the audio is not stored. When true, the audio for each generated segment is stored and you can retrieve it from your TTS history.

Message protocol

All control messages are JSON text frames. Audio is delivered as binary frames.

Client to server

message
Append text to the server’s buffer. This does not generate audio on its own.
message
Synthesize everything currently buffered and stream the audio back. The session stays open.
message
Signal that no more text is coming. The server flushes the remainder and finishes the session.

Server to client

message
A new audio segment is about to stream. Carries the segment index, the text being spoken, the format, and sample_rate (when known).
audio
One or more binary frames of audio for the current segment, in the negotiated response_format.
message
The current segment has finished streaming. Includes total_bytes and credits_utilized (the credits charged for this segment).
message
All segments are complete. The server will close the connection normally (1000).
message
An error occurred. Carries a message and, for terminal errors, a code matching the close code.

Audio format

Close codes

The connection closes with one of these codes. The close reason carries a short human-readable message.

Billing

WebSocket billing is per segment, at 1 credit per input character. Each segment is charged when it finishes (audio.done), based on the text you submitted for that segment. The credits_utilized field of each audio.done reports its cost. The server checks available credits before forwarding each input.text fragment for generation. If credits cannot cover the pending input, it sends an error frame with code 4402 and closes. Do not rely on receiving an unpaid final segment.

Limits

An oversized fragment or buffer overflow returns an error frame without closing the session. The rejected fragment is not added. Flush the existing buffer, then resend text in fragments that fit.

Example

Replace VOICE_ID with a voice UUID that supports chariot-multilingual-v1.
Python