# Prerecorded Transcribe a complete audio file. See the [Prerecorded guide](/speech-to-text/prerecorded/) for concepts. ``` POST https://api.reson8.dev/v1/speech-to-text/prerecorded ``` ## Request ### Headers | Header | Value | |---------------|-----------------------------------------------| | Authorization | `ApiKey ` or `Bearer ` | | Content-Type | `application/octet-stream` | See [Authentication](/authentication/) for which header to use in different situations. ### Query Parameters | Parameter | Type | Default | Description | |----------------------|---------|-----------|-----------------------------------------------------| | `encoding` | string | `auto` | Audio encoding: `auto` for detected container formats, `m4a`, `m4v`, `mp4`, `mov`, `3gp`, or `3g2` for explicit seekable media containers, `pcm_s16le` for raw PCM, or `mulaw` / `alaw` for raw G.711 telephony audio. See [Audio Formats](/speech-to-text/features/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](/speech-to-text/features/languages/) for supported codes | | `phrases` | string | | Comma-separated phrases to bias transcription toward, up to 250. See [Custom Models](/speech-to-text/features/custom-models/) | | `custom_model_id` | string | | ID of a [custom model](/api/custom-model/create/) 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 the response | | `include_confidence` | boolean | `false` | Include `confidence` on words | | `diarize` | boolean | `false` | Enable [speaker diarization](/speech-to-text/features/diarization/). Splits the response into per-speaker `segments` | | `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](/speech-to-text/features/patterns/) | | `filler_mode` | string | `natural` | Controls filler words in the transcript: `clean` removes them, `natural` lets the model decide, and `verbatim` preserves them | ### Example ```bash curl -X POST "https://api.reson8.dev/v1/speech-to-text/prerecorded" \ -H "Authorization: ApiKey " \ -H "Content-Type: application/octet-stream" \ --data-binary @recording.wav ``` ```python import requests with open("recording.wav", "rb") as f: response = requests.post( "https://api.reson8.dev/v1/speech-to-text/prerecorded", headers={ "Authorization": "ApiKey ", "Content-Type": "application/octet-stream", }, data=f, ) transcript = response.json() ``` ## Response `200 OK` ### Fields | Field | Type | Included | Description | |---------------|--------|--------------------------------------------------|-----------------------------------| | `text` | string | Always | Full transcript of the audio file | | `language` | string | When `include_language=true` and `diarize=false` | The detected language code. When `diarize=true`, language moves into each segment instead | | `start_ms` | number | When `include_timestamps=true` | Start time in milliseconds | | `duration_ms` | number | When `include_timestamps=true` | Duration in milliseconds | | `words` | array | When `include_words=true` and `diarize=false` | Word-level detail. When `diarize=true`, word detail moves into each segment instead | | `segments` | array | When `diarize=true` | Per-speaker segments. | Each segment contains: | Field | Type | Included | Description | |---------------|--------|--------------------------------|-----------------------------------------------------| | `text` | string | Always | Text spoken in this segment | | `language` | string | When `include_language=true` | The detected language code for this segment | | `speaker_id` | number | Always | Speaker label for this segment (integer, 0-indexed) | | `start_ms` | number | When `include_timestamps=true` | Start time in milliseconds | | `duration_ms` | number | When `include_timestamps=true` | Duration in milliseconds | | `words` | array | When `include_words=true` | Word-level detail for this segment | 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]` | ### Example ```json { "text": "the patient presented with chest pain and shortness of breath" } ``` With `diarize=true`, the response is split into per-speaker `segments`. ```json { "text": "where does it hurt my chest mostly and for how long about two days", "segments": [ { "text": "where does it hurt", "speaker_id": 0 }, { "text": "my chest mostly", "speaker_id": 1 }, { "text": "and for how long", "speaker_id": 0 }, { "text": "about two days", "speaker_id": 1 } ] } ``` ```json { "text": "where does it hurt my chest mostly", "start_ms": 0, "duration_ms": 3200, "segments": [ { "text": "where does it hurt", "language": "en", "speaker_id": 0, "start_ms": 0, "duration_ms": 1500, "words": [ { "text": "where", "start_ms": 0, "duration_ms": 250, "confidence": 0.990 }, { "text": "does", "start_ms": 260, "duration_ms": 200, "confidence": 0.980 }, { "text": "it", "start_ms": 470, "duration_ms": 150, "confidence": 0.990 }, { "text": "hurt", "start_ms": 630, "duration_ms": 870, "confidence": 0.970 } ] }, { "text": "my chest mostly", "language": "en", "speaker_id": 1, "start_ms": 1700, "duration_ms": 1500, "words": [ { "text": "my", "start_ms": 1700, "duration_ms": 180, "confidence": 0.990 }, { "text": "chest", "start_ms": 1890, "duration_ms": 400, "confidence": 0.960 }, { "text": "mostly", "start_ms": 2300, "duration_ms": 900, "confidence": 0.980 } ] } ] } ``` ## Errors Errors are returned as `application/problem+json` (RFC 7807) with a lowercase `code` field. | Status | Code | Description | |---------------------------|---------------------------|-------------------------------------------------------------| | 400 Bad Request | `invalid_audio` | Undecodable audio | | 400 Bad Request | `invalid_query_parameter` | Invalid query parameter | | 400 Bad Request | `session_rejected` | Unknown `custom_model_id`, or `patterns` combined with a custom model | | 401 Unauthorized | `unauthorized` | Missing or invalid credentials | | 402 Payment Required | `session_rejected` | Credit limit exceeded - see [Limits](/limits/) | | 413 Payload Too Large | | Request body exceeds the size limit (no `code` in the body) | | 429 Too Many Requests | `session_rejected` | Concurrent connection limit exceeded - see [Limits](/limits/) | | 500 Internal Server Error | `internal_server_error` | Unexpected server error |