POST /v1/audio/transcriptions
Transcribe audio (unit-billed, audio-seconds)
Task #15 specialty route (route_type: transcriptions); seam contract updated task #17 (batch leg). Batch variant (default): the CLIENT face is multipart/form-data, but the GATEWAY translates at the seam — the file part's bytes cross to the upstream as the RAW request body under the file part's Content-Type, and a non-empty language field forwards as the upstream ?lang=<code> query (the card owns the dedicated-code whitelist); JSON response passthrough. language is required in practice: omitted or non-dedicated reaches the card's default path and the client receives a 502 relayed VERBATIM — terminal, non-retryable, the one non-gateway-envelope error on this surface (do not retry the same language). Body-shape law (proven live, task #17 E1): the card's in-cluster JSON error body never crosses the Salad edge (Cloudflare replaces origin 5xx bodies with its own "error code: 502" text page), so clients see the edge's page and the gateway keys the terminal on the 502 status alone. Accepted form fields — file (required), model (required), language, prompt, response_format, temperature, stream; unknown fields are 400 unknown_param; prompt / response_format / temperature are accepted then DROPPED on the batch leg (the card never consumed them). Supported containers = the card's decode set (WAV / FLAC / Ogg-Opus) within the 25 MiB upload cap (413); an undecodable upload is 502 upstream_rejected (the card's reason lands in the ops log, not the client body); effective request ceiling ≈ 240 s — client-side chunking for longer audio. Streaming variant (stream=true): response is text/event-stream — data lines carrying {"type":"transcription.partial"|"transcription.final"|"transcription.refine","text":...} events (refine additionally carries the auto-detected "lang" — additive metadata, never meters), ": ping" keep-alive before the first event, terminal data: [DONE]; the stream ends at [DONE] after the card's own close OR a short post-event idle (the card ends a session by going silent — task #17 live law; silence-after-events is a clean end, not an error), while a mid-stream upstream DEATH ends with the §6 terminal error event. Streaming accepts raw PCM/WAV only (audio/L16;rate=16000 family — anything else is 400 unsupported_audio_format); language is AUTO-DETECTED on the stream (no selection in the WS protocol — the refine event carries the detected code). Metering: unit_type='audio_seconds' = ceil of the upstream-reported duration (streaming: the sum of final-event durations), else — batch only — the wall-clock; the streaming fallback is the uploaded PCM's own duration, ceil(len/32000) at 16 kHz s16le mono (duration_source:"pcm_bytes", task #17 review F-1 — wall-clock billed dial + upload + the idle-detect tail ~2x over). Idempotency-Key: accepted, no replay semantics (§8 route-scope).
Request
The body is multipart/form-data — one part per field below; the sample sends it
with curl -F legs (curl owns the boundary — no Content-Type header).
Request body fields for createTranscription | Field | Type | Required | Description |
| file | string (binary) | yes | The audio file (≤ 25 MiB). |
| model | string | yes | An IronStratum alias whose route_type is transcriptions. |
| language | string | no | Required in practice on hayamimi-stt — forwarded as the upstream ?lang= query; omitted/non-dedicated codes get the card's 502 non_dedicated_language body verbatim. Optional on whisper (auto-detected when omitted; forwarded as a form field on the provider's native seam).
|
| prompt | string | no | — |
| response_format | string | no | — |
| temperature | string | no | — |
| stream | string | no | "true" selects the SSE streaming variant. |
Responses
400 400
400 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
401 401
401 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
402 402
402 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
403 403
403 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
404 404
404 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
413 413
413 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
500 500
500 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
502 502
502 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
503 503
503 response fields for createTranscription | Field | Type | Required | Description |
| error | object | yes | — |
Status codes
- 200 — Batch: the upstream JSON response verbatim. stream=true: text/event-stream of transcription events ending [DONE].