wss://stt.api.rime.ai/ws from your backend, stream audio, and read the transcript as it arrives. If your backend is in Python, Node.js, Go, or Rust, use the Rime SDK instead, because it connects over gRPC and needs less code. The exception is a long recording, which needs this API’s append fragments. For other languages, read Choose how to connect first. That section helps you choose between this endpoint and gRPC, and between the two output contracts.
Session at a glance
Guarantees
Connection
Response encoding
Set the response encoding in theSec-WebSocket-Protocol header of the upgrade request:
The response encoding stays the same for the whole connection. The subprotocol sets only the response encoding, because the server decodes each client message by its frame type. For example, you can send JSON text frames and receive protobuf. Both encodings carry the
SpeechWebSocketRequest and SpeechWebSocketResponse envelopes, which the speech-to-text schema defines. JSON uses the canonical proto3 mapping:
Upgrade responses
The server answers the upgrade request with one of these HTTP statuses. A refusal is a plain-text HTTP response, and it arrives before any event:Messages
Send
Start
start opens the utterance. outputContract and language are required. mode and contextTerms are optional, and they work the same way under both output contracts. Start parameters describes each field.
es in started:
Audio
Eachaudio message carries one chunk of audio, and it must meet these requirements:
All of the decoded audio for the utterance must fit in 16 MiB. Within that limit, your client sets the chunk size by how many bytes it puts in each
audio message. It sets the pace by when it sends each message. 100 ms of audio is 3,200 bytes, and you can send a recording faster than real time. Limits lists the error kind for each limit.
End
end ends the audio and commits the utterance. After you send it, keep reading:
Cancel
cancel stops the utterance and the work that Rime does on it. You can send it before or after end:
Receive
Started
started confirms that the server accepted your start.
The session for the flight recording used English and revised hypotheses. It started with this event:
Hypothesis
Under revised hypotheses, eachhypothesis is a partial transcript.
This is the second of the four hypotheses in that session:
Delta
Under append fragments, the server transcribes each five-second window of audio one time, on its own. It sends the text of the window as adelta, and a window with no recognized text produces no delta.
Under append fragments, the same recording produced two deltas. The second delta starts with the newline separator:
done.text of that session was the two deltas joined in order: "Hi! I'm calling about flight 247 to Denver.\nCan I move it to Friday?". Append fragments also suit a recording that is too long for a revised-hypotheses session, because the model’s context does not grow during the session. Transcribe a long recording has the steps and the limits that still apply.
Done
A successful utterance ends with onedone event, then a Close frame. Under both contracts, language confirms the language.
done event for the flight recording, under revised hypotheses:
Error
error ends a failed utterance. If the connection is still writable, a Close frame follows.
A
start message without outputContract fails with invalid_input:
Cancelled
cancelled confirms your cancel. If the connection is still writable, a Close frame follows.
Start parameters
string
required
Set one of these two values. There is no default, and an omitted, unspecified, or unknown value fails with
invalid_input. Compare the two contracts to choose between them:string
required
The spoken language:
en or es. The service does not detect the language. An omitted tag, und, an unsupported language, or a malformed tag fails with invalid_input.string
default:"TRANSCRIPTION_MODE_WRITTEN"
Set one of these values. The mode guides the model, but it does not guarantee exact output.
string[]
Recognition hints, such as
["Northwind Air", "FlexPlus", "Okonkwo"]. The terms make the model more likely to recognize them, but they do not force a match. The context-term rules apply, and a value that breaks one fails with invalid_input:Limits
The idle timer and model context follow some more rules.
Transcribe a long recording
Some recordings are too long for one revised-hypotheses stream. Send them through the direct API with append fragments. Rime recognizes each five-second window on its own, so the model’s context does not fill up as the recording continues. For now, only the direct API can do this, because the SDK receives only revised hypotheses.- Open a WebSocket stream, or a gRPC
TranscribeStreamingcall, withSTREAMING_OUTPUT_CONTRACT_APPEND_FRAGMENTS. - Send the audio as fast as the connection accepts it, not at the speed of the recording. The 120-second limit is wall-clock time from connecting to
done, not the length of the audio. - Keep each stream within the 16 MiB audio limit, which is about 8.7 minutes of 16 kHz mono PCM16. Send a longer file in parts, with one stream for each part. Join the
done.textvalues of the parts in order, with a newline between them, because a newline also separates deltas.
Complete Python client
This client streams a 16 kHz mono PCM16 WAV file over the WebSocket API. It opens the file with Python’swave module, and it sends the samples without the header, as fast as it reads them. As the hypotheses arrive, the client replaces the console line with each one. At the end, it prints the final done result. The client uses revised hypotheses, which suit a short file. For a long recording, use append fragments.
Before you run the client:
- Download the sample recording.
- Set
RIME_API_KEYin the environment of your backend. - Install
websockets14 or later withpip install "websockets>=14". The client uses theadditional_headersargument of that version.
- Install FFmpeg.
-
Convert the recording. This command reads
input.m4a, or any other format that FFmpeg can decode. It writessample.wavas 16 kHz mono PCM16, and it keeps the WAV header.The conversion in the quickstart writes headerless PCM instead, whichwave.open()rejects.
transcribe_ws.py
transcribe_ws.py
transcribe_ws.py
python transcribe_ws.py flight.wav. A successful run prints the request ID, then the latest hypothesis on one line, and then the done result. A recording with no speech can return done with no text.
