Realtime HTTP API

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.

POST/http/stt

Transcribe 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
X-Api-Key<token>

In: header

Query Parameters

id*string

Fresh client-generated correlation UUID. It is not an idempotency key.

language?string

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.

asr?string

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.

model?string

Alias for asr.

lang?string

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.

On this page