Skip to main content
Connect to 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 the Sec-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.
This start message asks for English with revised hypotheses. It adds recognition hints for an airline, a fare name, and a caller’s surname:
This minimal start message selects append fragments for Spanish. It uses the default written mode, and the server confirms es in started:

Audio

Each audio 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.
This JSON shows the shape of the message. The example shortens the base64 value:

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, each hypothesis 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 a delta, 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:
The 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 one done event, then a Close frame. Under both contracts, language confirms the language.
This is the 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.
  1. Open a WebSocket stream, or a gRPC TranscribeStreaming call, with STREAMING_OUTPUT_CONTRACT_APPEND_FRAGMENTS.
  2. 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.
  3. 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.text values 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’s wave 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:
  1. Download the sample recording.
  2. Set RIME_API_KEY in the environment of your backend.
  3. Install websockets 14 or later with pip install "websockets>=14". The client uses the additional_headers argument of that version.
To use your own recording, convert it to a WAV file in the same format:
  1. Install FFmpeg.
  2. Convert the recording. This command reads input.m4a, or any other format that FFmpeg can decode. It writes sample.wav as 16 kHz mono PCM16, and it keeps the WAV header.
    The conversion in the quickstart writes headerless PCM instead, which wave.open() rejects.
transcribe_ws.py
Run the client with the file name, for example 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.