Endpoint
Authenticating
Send your API key in thechariotai-api-key header on the WebSocket handshake. If your client cannot set handshake headers, pass it as the api_key query parameter instead:
error event and closes with code 1008.
How a session works
1
Connect
Open the WebSocket with your options in the query string. The server replies with
session.started. Wait for it before sending audio.2
Stream audio
Send audio as binary frames as you capture it.
transcript.delta events arrive with new text as it is recognized.3
Finish
Send
input.done after your last frame. The server transcribes the remaining audio, sends transcript.done with the complete transcript, and closes with code 1000.Connection parameters
Pass these as query parameters on the connection URL. All are optional.string
default:"pcm_16000"
Encoding and sample rate of the audio you send, always mono. One of
pcm_8000, pcm_16000, pcm_22050, pcm_24000, pcm_32000, pcm_44100, pcm_48000 (signed 16-bit little-endian PCM at that rate), ulaw_8000 (G.711 mu-law), or alaw_8000 (G.711 A-law). Declare the rate you actually send. See Audio formats.string
Language hint for the session:
en, hi, bn, gu, kn, ml, mr, or, pa, sa, ta, or te. Omit it, or pass none, for automatic language detection. It does not translate. See Languages.string
default:"balanced"
balanced prioritizes responsiveness, for interactive applications. high_accuracy allows more context before committing text, which increases latency and usually gives more accurate transcripts. See Modes.string
default:"codemix"
How mixed-language speech is written.
codemix keeps borrowed words, usually English, in their own script. native writes everything in the script of the spoken language. See Styles.string
default:"chariot-1-asr-realtime"
The speech-to-text model.
chariot-1-asr-realtime is the default and only value.number
default:"60"
Seconds the server waits for your next message, audio or JSON, before closing the session as idle. Must be greater than 0 and at most 300. A value outside that range rejects the connection.
string
Your API key, for clients that cannot set the
chariotai-api-key header.Client to server
Audio (binary frames)
Send audio as binary WebSocket frames in the declaredaudio_format. Each frame is raw samples, not a file: no WAV header, no JSON, no base64.
Any frame size works, and a frame does not have to end on a sample boundary. Frames of about 100 ms are a good default, for example 3,200 bytes at pcm_16000. See chunk size.
keepalive
Keeps the session open while you have no audio to send, for example while a microphone is muted. It resets the idle timer. The server does not reply.
input.done
Signals that no more audio is coming. The server transcribes everything it has received, sends any remaining transcript.delta events and then transcript.done, and closes with 1000. Audio sent after input.done is not transcribed.
type gets an error event without a code, and the session continues.
Server to client
The server sends JSON text frames only.event
The session is ready for audio. Sent once, first. Echoes the settings in effect.
event
New text, as it is recognized. Each delta adds to the text before it, so append
text to what you have shown so far. Spaces are included in text, so concatenate deltas without adding separators.event
The complete transcript, sent once after Treat
input.done. audio_seconds is the duration of the audio you sent. The connection then closes with 1000.text here as the final result, and use it in place of the deltas you accumulated.event
The session will reach
max_duration_seconds soon. Sent once, about a minute before the limit.event
Something went wrong. When the event has a
code, the error is terminal: the server closes the connection with that same close code. Without a code, the error concerns a single message and the session continues.Keeping a session open
The server closes a session as idle when it receives no message foridle_timeout seconds (60 by default). Every audio frame and every JSON message resets the timer. An idle close sends an error event with code 1008 and closes with 1008.
If you pause the audio, send {"type": "keepalive"} more often than the idle timeout, for example every 10 to 20 seconds. Sessions that end on an idle timeout do not get a transcript.done. The text recognized up to that point arrived in transcript.delta events and is saved in history.
Text for your most recent speech arrives only after more audio follows it, and
high_accuracy holds back more of it than balanced. With a live source, keep streaming through pauses, silence included, so that text arrives during the pause. While you send only keepalive, it waits until audio resumes or you send input.done. When you have no more audio, send input.done to get the final text.Session length
A session can run for up tomax_duration_seconds, announced in session.started (currently 10,800 seconds, three hours). About a minute before the limit, the server sends session.expiring. At the limit it sends an error event with code 4413 and closes with 4413, without a transcript.done.
To transcribe a stream longer than the limit, open a new session when session.expiring arrives, move your audio to it, and send input.done on the old session to collect its final transcript.
Concurrency
Each open session uses one speech-to-text concurrency slot for its entire life, including pauses, until the connection closes. The number of slots depends on your plan. When every slot is in use, a new session gets anerror event and closes with 4429. See Rate limits & concurrency.
Close sessions you no longer need, and send input.done rather than leaving a finished session open until it times out.
Billing
Streaming costs 1.5 credits per second of audio you send, at any sample rate or encoding. Time with the connection open but no audio sent, such as keepalive-only pauses, is not billed. Silence you send as audio is billed like any other audio. Credits are charged periodically while the session runs and settled when it closes. A session’s total is the audio duration multiplied by 1.5, rounded up to a whole credit. To open a session, your workspace needs a small minimum balance (currently 30 credits). Otherwise the server sends anerror event with code 4402 and closes. If your balance runs out during a session, the server sends an error event with code 4402 and closes, without a transcript.done. See Credits & pricing.
Close codes
The
error event’s message explains the cause. Branch on the code, not on the message text. When a session fails to start, nothing is billed.
Best practices
- Declare the right format. Audio sent at a different rate than
audio_formatdeclares is transcribed as the wrong speech, without an error. - Wait for
session.startedbefore sending audio, and readmax_duration_secondsfrom it. - Send about 100 ms per frame from live sources, as you capture it.
- Always end with
input.doneto gettranscript.done. Closing the socket yourself skips it. - Use
transcript.doneas the final text. Deltas are for live display. - Handle
1011by reading theerrormessage: if it names an option to change, reconnect with that value; otherwise reconnect after a short delay. On4429, wait for another session to finish, or retry with backoff. - Set
languagewhen you know it. Omit it for mixed or unknown speakers.
Example: keepalive during pauses
This Python fragment sends audio from a queue and falls back to keepalive messages while the queue is empty, for example while a microphone is muted:Python