webhook_url, get a job id at once, and receive the result on your server when it is ready. Works with the
native API and with OpenAI model names (OpenAI SDK: extra_body), with every option (normalize, mode, diarize,
gender_detection, hints, hint_context, speaker_lock, voice_isolation, response_format including the OpenAI
formats). Live streaming is unchanged.
Not combinable with
stream=true. Maximum audio length: 4 hours.
1. Submit → 202
duration is counted once, when the job is accepted (this 202); status reads and the webhook are
not counted. Errors in the request (unknown option, language, bad webhook_url or file_url, unreadable audio) come
at once as 400, exactly like a synchronous request.
2. Webhook
POST to webhook_url, Content-Type: application/json:
resultis the body the same synchronous request answers: the native JSON, or the OpenAI body for OpenAI model names ({"text", "usage", …},verbose_json,diarized_json);text,srtandvttcome as a string. (A job decodes the ~28-second parts of a long file one at a time, so a few words of a long file can differ from a synchronous run, as they also can between two synchronous runs under different load.)eventsays what finished:transcription.completedortranscription.failed(also in theX-Mihu-Eventheader).messageis the same in one human-readable line.sourceis the audio:\{"type": "upload", "filename", "size_bytes"\}or\{"type": "file_url", "url", "filename", "size_bytes"\}(the URL without its query string, so pre-signed credentials are never echoed).requestlists the options the job ran with, defaults filled in. Yourwebhook_metadatacomes back asmetadata.- Job ids are UUIDs.
- On failure:
"event": "transcription.failed","status": "failed"and"error": {"status": 400, "message": "…"}instead ofresult. - Headers:
X-Mihu-Webhook-Id(= job id, the same on every attempt: use it to ignore duplicates),X-Mihu-Event,X-Mihu-Timestamp(Unix seconds),X-Mihu-Attempt, and with a secretX-Mihu-Signature: sha256=<hex HMAC-SHA256(webhook_secret, "\{timestamp\}.\{raw body\}")>. - Answer with any
2xxwithin 10 seconds (store the body, process it later). Anything else, a timeout or a redirect counts as a failed attempt; it is retried after 1 s, 10 s, 1 min, 5 min and 30 min (6 attempts, ~36 minutes), then given up (the result can still be read withGETuntil it expires).
3. Status and result: GET /v1/audio/transcriptions/{id}
Same API key (tenant) as the request that created the job; any other key gets 404.
status: queued → processing → completed | failed. progress (0–1) while processing where it can be measured
(model=umay), else null. Once completed the answer also has event, message and result (or error), and webhook.state shows the
delivery: pending, delivered, failed. Polling instead of a webhook is fine (every 10–30 s).
Data retention
- The audio is deleted as soon as recognition has finished (uploaded and downloaded files right after decoding; the decoded audio kept for a queued job is deleted when the job ends).
- The job with its result is deleted 1 hour after completion; afterwards
GETanswers404. Transcripts are not kept longer. Everything stays on the server of the region you call.
OpenAI SDK
202 from the raw response as above. The webhook’s result
is the OpenAI body of the chosen response_format. webhook_metadata may also be a dict in extra_body (the SDK sends
it as webhook_metadata[key] fields; it comes back as an object with string values).
Downloading from a URL: file_url
202 arrives. Without
webhook_url the request waits for the result as usual.