Stream fast transcription for one complete audio unit
Transcribe one complete, bounded, latency-sensitive audio unit, such as one finished user turn in an agentic conversation or a voice command.
/http/sttTranscribe one complete, bounded, latency-sensitive audio unit, such as one finished user turn in an agentic conversation or a voice command. Use Batch for long or large complete recordings, and Realtime ASR while audio is still arriving.
This is a direct HTTP operation. SDK 0.18.0 Fast clients use Socket.IO;
they do not call this route. Send the request from a trusted backend with
X-Api-Key and the realtime ASR capability.
Supply a unique UUID in id and one complete audio file in the multipart
field file. A nonempty language takes precedence over lang; a
nonempty asr takes precedence over model. Omitted or auto language
and an omitted model use defaults configured for the environment. Fast
applies only language and ASR model selection; use Batch when
diarization, ITN, or redaction is required.
The response is NDJSON. A request can emit partial transcription records
before the final record. If a later callback fails after output was
flushed, the partial 200 stream ends without an appended JSON error.
Require exactly observed is_final: true for completion, and treat EOF,
cancellation, or an application deadline without a final record as
incomplete. seq is opaque diagnostic data and has no ordering or
uniqueness guarantee.
Limits
Two independent bounds apply, and they measure different things.
The whole multipart request body must not exceed 64 MiB
(67108864 bytes). Exceeding it is 413 with code PAYLOAD_TOO_LARGE
and data.bound: fast_audio_bytes.
The audio must not DECODE to more than 1800 seconds (30 minutes).
Exceeding it is 422 with code AUDIO_DURATION_EXCEEDED and
data.bound: fast_audio_duration. This is a separate bound because a
small compressed upload can decode to many hours: a request that is
perfectly acceptable in bytes can still ask for more audio work than
this endpoint performs. Both bounds are inclusive - exactly at the limit
succeeds, and only strictly over it fails.
The service enforces the duration bound from the container header where
the file declares its own length, from container metadata where the
decoder can read it, and otherwise while decoding, stopping at the
ceiling. Over-long audio is therefore refused before any inference, and
consumes no audio-capacity credit. Deployments can override both bounds
with REALTIME_MAX_BODY_BYTES_FAST_TRANSCRIPTION and
REALTIME_MAX_FAST_AUDIO_DURATION_SEC, so this schema does not declare
a fixed maxLength.
For recordings longer than 30 minutes, or larger than 64 MiB, split the audio into shorter units or use the batch transcription API, whose ceiling is 4 hours per file.
Audio format
The payload must be AAC (ADTS), FLAC, MP3, WAV, or an ISO base media
file. The container is identified by the server from the payload itself,
never from a filename or a media type, and anything else is rejected with
400 and code ASR_UNSUPPORTED_CODEC even when it is otherwise
decodable.
The ISO base media entry is a family: MP4 is the intended and supported
form, and MOV, M4A, 3GP, 3G2 and MJ2 share one demuxer with it and are
therefore admitted by the same check. Only MP4 is tested and intended; do
not build on the others. Put the moov atom at the FRONT of the file -
not a policy the server rejects on, but a practical requirement, because
the upload is read forward-only and a trailing moov cannot be reached.
Sample rate and channel count are not restricted: audio is resampled and downmixed to mono at the sample rate configured for the selected ASR model, which the client does not choose.
Apply finite connect, inactivity, and overall deadlines. This operation has no idempotency or replay contract; do not blindly resubmit after an ambiguous timeout or disconnect.
Authorization
ApiKeyAuth In: header
Query Parameters
Fresh client-generated correlation UUID. It is not an idempotency key.
Language for transcription. Alias lang is also accepted.
A nonempty language takes precedence over lang. Blank or auto
resolves to the default configured for the environment, currently
the code-switching model.
Optional exact ASR model key; model is also accepted as an alias.
A nonempty asr takes precedence. If both are omitted, the service
uses the configured default for the selected language.
Alias for asr.
Alias used only when language is omitted or empty.
Request Body
multipart/form-data
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/x-ndjson
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -sS --fail-with-body --connect-timeout 10 --max-time 120 -X POST \ "https://example.com/http/stt?id=497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Origin: https://example.com" \ -F "file=@meeting.wav"Zero or more transcription NDJSON records. Once output has started,
a later failure ends the partial stream without an appended JSON
error. Completion requires an observed record with is_final: true.
application/x-ndjson
Example partial
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello wor",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
}
],
"is_final": false
}Example final
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello world",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
},
{
"start_time": 0.46,
"end_time": 0.9,
"word": "world"
}
],
"is_final": true
}Invalid request ID, language, multipart upload, audio container, or ASR
model. Every case here is client-fixable, so none of them is ever
reported as a 5xx.
application/json
Invalid request ID
{
"error": "invalid request id",
"code": "VALIDATION_INVALID_UUID",
"detail": "invalid request id",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}Invalid language
{
"error": "invalid language",
"code": "VALIDATION_INVALID_LANGUAGE",
"detail": "invalid language",
"job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}Invalid multipart file upload
{
"error": "invalid file upload",
"code": "VALIDATION_FILE_CORRUPT",
"detail": "invalid file upload",
"job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}Audio container is outside the published set
The payload must be AAC (ADTS), FLAC, MP3, WAV, or an ISO base
media file. A container the decoder could otherwise read is still
refused, so this is a contract decision rather than a decode
failure. Re-encode and resubmit; the identical bytes cannot
succeed. See "Audio format" on the operation for the exact
accepted set and for why moov placement is a practical
requirement rather than something the server rejects on.
{
"error": "audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV",
"code": "ASR_UNSUPPORTED_CODEC",
"detail": "audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV",
"job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}ASR model is not configured
{
"error": "ASR model not found",
"code": "ASR_MODEL_NOT_FOUND",
"detail": "ASR model not found",
"job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}Unauthorized
application/json
Example missing_key
{
"error": "Invalid authentication",
"code": "AUTH_UNAUTHORIZED",
"detail": "Invalid authentication",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}The API key does not grant access to the requested voice capability
application/json
Example scope_denied
{
"error": "scope not permitted",
"code": "AUTH_FORBIDDEN",
"detail": "scope not permitted",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}Method not allowed
application/json
Example wrong_method
{
"error": "method not allowed",
"code": "METHOD_NOT_ALLOWED",
"detail": "method not allowed",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}The request body exceeded the configured byte limit for this audio route: 64 MiB for Fast uploads, 16 MiB for Realtime ASR frames, 16 MiB for Realtime diarization frames. Non-retryable at the same size; resend a smaller unit or chunk.
data.bound names which byte limit was hit - fast_audio_bytes,
realtime_asr_frame_bytes, or realtime_diarization_frame_bytes.
data.observed is the exact request size when the client declared a
Content-Length, and otherwise a MINIMUM (the limit plus one byte),
because a body with no declared length is cut off mid-read and its true
size is never learned.
This status is only ever reached from a BYTE count. A request whose bytes
are acceptable but whose decoded audio is too long is 422 with
AUDIO_DURATION_EXCEEDED instead.
application/json
Content-Length was declared, so observed is exact
{
"error": "request body too large",
"code": "PAYLOAD_TOO_LARGE",
"detail": "request body too large",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"limit": 16777216,
"observed": 20971520,
"unit": "bytes",
"bound": "realtime_asr_frame_bytes"
}
}No declared length, so observed is the limit plus one byte
{
"error": "request body too large",
"code": "PAYLOAD_TOO_LARGE",
"detail": "request body too large",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"limit": 67108864,
"observed": 67108865,
"unit": "bytes",
"bound": "fast_audio_bytes"
}
}The request parsed correctly and its bytes were acceptable, but the
amount of AUDIO it asks the service to process exceeds this endpoint's
ceiling (RFC 9110 15.5.21). A small compressed upload that decodes to
many hours is exactly this case, which is why it is not 413.
data.bound names which audio ceiling was hit:
fast_audio_duration- one Fast submission decoded to more than 1800 seconds. Split the recording or use the batch transcription API.session_audio_duration- a realtime session has now sent more total audio content than its 14400-second (4 hour) allowance. The session is retired; start a new one.
data.observed is in whole seconds, rounded up. Where the service
stopped decoding at the ceiling it never learned the true total length,
so the observed value is a MINIMUM rather than an exact measurement.
Not retryable: resending the identical audio cannot succeed. Shorten the unit, or move to the batch API.
application/json
Example fast_decoded_audio_too_long
{
"error": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
"code": "AUDIO_DURATION_EXCEEDED",
"detail": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"limit": 1800,
"observed": 3601,
"unit": "seconds",
"bound": "fast_audio_duration"
}
}Example session_audio_allowance_spent
{
"error": "session maximum audio duration exceeded; start a new session",
"code": "AUDIO_DURATION_EXCEEDED",
"detail": "session maximum audio duration exceeded; start a new session",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"limit": 14400,
"observed": 14401,
"unit": "seconds",
"bound": "session_audio_duration"
}
}Gateway rate limiting. Response details and retry headers are deployment-specific.
Fast transcription failed before a final record was emitted
application/json
Example transcription_failed
{
"error": "STT transcription failed",
"code": "ASR_TRANSCRIPTION_FAILED",
"detail": "STT transcription failed",
"job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z"
}Next steps
Use Fast only after one bounded conversational audio unit is complete. Parse every NDJSON record, commit output only from a final record, and keep long recordings such as podcasts and meetings on Batch.