Realtime
Real-time speech-to-text transcription over WebSocket. See the Realtime guide for concepts.
wss://api.reson8.dev/v1/speech-to-text/realtimeRequest
Section titled “Request”Headers
Section titled “Headers”| Header | Value |
|---|---|
| Authorization | ApiKey <api_key> or Bearer <access_token> |
| Sec-WebSocket-Protocol | bearer, <access_token> |
See Authentication for which header to use in different situations.
Query Parameters
Section titled “Query Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
encoding |
string | auto |
Audio encoding: auto for detected container formats, pcm_s16le for raw PCM, or mulaw / alaw for raw G.711 telephony audio. See Audio Formats |
sample_rate |
number | 16000 |
Sample rate in Hz (only used depending on encoding) |
channels |
number | 1 |
Number of audio channels, 1-10 (only used depending on encoding) |
language |
string | Language to transcribe. Recommended for best quality. A comma-separated list (e.g. nl,en) constrains per-utterance auto-detection to those candidates. When omitted, the server auto-detects each utterance independently. See Languages for supported codes |
|
phrases |
string | Comma-separated phrases to bias transcription toward, up to 250. See Custom Models | |
custom_model_id |
string | ID of a custom model to bias transcription. Overrides the model configured on the API client | |
bias_strength |
number | 0.45 |
Strength of contextual biasing. Must be a non-negative number |
include_timestamps |
boolean | false |
Include start_ms and duration_ms on transcripts and words |
include_words |
boolean | false |
Include word-level detail on transcripts |
include_language |
boolean | false |
Include the detected language on transcripts (empty on interim) |
include_confidence |
boolean | false |
Include confidence on words |
include_interim |
boolean | false |
Include interim (partial) results and the is_final flag |
diarize |
boolean | false |
Enable speaker diarization. Adds speaker_id to each transcript |
max_speakers |
number | Maximum number of distinct speakers (1-4). When omitted, the count is determined automatically. Only used when diarize=true |
|
patterns |
string | Comma-separated regex-style patterns for short alphanumeric tokens (order codes, licence plates) to recover. Only set when the token is likely present; cannot be combined with phrases or a custom model - see Patterns |
|
filler_mode |
string | natural |
Controls filler words in final transcripts: clean removes them, natural lets the model decide, and verbatim preserves them. Interim transcripts are unaffected |
Example
Section titled “Example”import asyncioimport jsonimport websockets
async def transcribe(): url = "wss://api.reson8.dev/v1/speech-to-text/realtime" headers = {"Authorization": "ApiKey <your_api_key>"}
async with websockets.connect(url, additional_headers=headers) as ws: async def send_audio(): try: with open("recording.wav", "rb") as f: while chunk := f.read(8192): await ws.send(chunk) await ws.send(json.dumps({"type": "flush_request"})) except Exception: await ws.close() raise
sender = asyncio.create_task(send_audio())
async for message in ws: event = json.loads(message) print(event) if event["type"] == "flush_confirmation": break
await sender
asyncio.run(transcribe())const token = "<your_access_token>";const url = "wss://api.reson8.dev/v1/speech-to-text/realtime";
// Passes token via Sec-WebSocket-Protocol headerconst ws = new WebSocket(url, ["bearer", token]);
ws.onopen = async () => { const audio = await (await fetch("/recording.wav")).arrayBuffer(); for (let i = 0; i < audio.byteLength; i += 8192) { ws.send(audio.slice(i, i + 8192)); } ws.send(JSON.stringify({ type: "flush_request" }));};
ws.onmessage = (event) => { const message = JSON.parse(event.data); console.log(message); if (message.type === "flush_confirmation") ws.close();};Sending Messages
Section titled “Sending Messages”Binary WebSocket frame containing audio data.
Flush Request
Section titled “Flush Request”Force the server to finalize any buffered audio and return a transcript.
{ "type": "flush_request", "id": "abc123"}| Field | Type | Required | Description |
|---|---|---|---|
id |
string | No | Optional identifier, returned in the corresponding flush confirmation |
Receiving Messages
Section titled “Receiving Messages”Transcript
Section titled “Transcript”Returned when speech is recognized. By default, only final results are returned. When include_interim=true, interim (partial) results are also returned - these may change as more audio is processed.
{ "type": "transcript", "text": "the patient presented with chest pain"}With diarize=true, each transcript carries the speaker_id of its dominant speaker.
{ "type": "transcript", "text": "where does it hurt", "speaker_id": 0 }{ "type": "transcript", "text": "my chest, mostly", "speaker_id": 1 }{ "type": "transcript", "text": "the patient presented with chest pain", "language": "en", "is_final": true, "start_ms": 1200, "duration_ms": 2400, "speaker_id": 0, "words": [ { "text": "the", "start_ms": 1200, "duration_ms": 200, "confidence": 0.990 }, { "text": "patient", "start_ms": 1410, "duration_ms": 450, "confidence": 0.980 }, { "text": "presented", "start_ms": 1880, "duration_ms": 500, "confidence": 0.970 }, { "text": "with", "start_ms": 2400, "duration_ms": 200, "confidence": 0.990 }, { "text": "chest", "start_ms": 2620, "duration_ms": 350, "confidence": 0.960 }, { "text": "pain", "start_ms": 3000, "duration_ms": 600, "confidence": 0.970 } ]}| Field | Type | Included | Description |
|---|---|---|---|
text |
string | Always | The recognized text |
language |
string | When include_language=true |
The detected language code (empty on interim) |
is_final |
boolean | When include_interim=true |
true for final, false for interim |
start_ms |
number | When include_timestamps=true |
Start time in milliseconds |
duration_ms |
number | When include_timestamps=true |
Duration in milliseconds |
speaker_id |
number | When diarize=true |
Speaker label for this transcript (integer, 0-indexed). See Diarization |
words |
array | When include_words=true |
Word-level detail |
Each word contains:
| Field | Type | Included | Description |
|---|---|---|---|
text |
string | Always | The recognized word |
start_ms |
number | When include_timestamps=true |
Start time in milliseconds |
duration_ms |
number | When include_timestamps=true |
Duration in milliseconds |
confidence |
number | When include_confidence=true |
Probability in (0, 1] |
Flush Confirmation
Section titled “Flush Confirmation”Sent after a flush request has been processed. The id field is always present; it is null if no identifier was provided in the request.
{ "type": "flush_confirmation", "id": "abc123"}| Field | Type | Included | Description |
|---|---|---|---|
id |
string | Always | The identifier from the corresponding flush request, or null if none was provided |
Errors
Section titled “Errors”Rejected WebSocket upgrades return no body; where available, the reason is in the X-Error-Message response header.
| Status | Description |
|---|---|
| 400 Bad Request | Invalid query parameter, unknown custom_model_id, or patterns combined with a custom model |
| 401 Unauthorized | Missing or invalid credentials |
| 402 Payment Required | Credit limit exceeded - see Limits |
| 429 Too Many Requests | Concurrent connection limit exceeded - see Limits |
During the Session
Section titled “During the Session”If an unrecoverable error occurs after the connection is established, the server closes the WebSocket without sending an error message. Treat an unexpected close as an error and reconnect with a fresh audio stream. Malformed or unrecognized client messages are ignored; the session continues.