API Guides

Batch transcription

Submit long complete recordings, poll every terminal state, and handle capacity safely.

Use Batch REST when a large or long recording already exists and asynchronous completion is acceptable. It fits meetings, podcasts, archives, and similar complete files: upload once, receive a jobId, and poll the job to a terminal state.

Fast transcription also accepts complete audio, but choose it for one latency-sensitive conversational unit. If audio is still arriving, use a realtime workflow instead.

1. Prepare a trusted server

Direct batch requests need the following values and decisions:

RequirementWhat to prepare
API_URLUse the exact REST base URL issued for your environment; don't infer a host
API_KEYSend it as x-api-key from a trusted backend, never public client code
Complete audioUpload one file in the file field of a multipart/form-data body
DeadlinesSet a timeout on each request and a finite deadline for the whole job

Follow the authentication flow to obtain API_KEY. This site renders the API_URL configured for its environment. API_PATH is a Socket.IO setting and isn't used by these REST routes.

2. Submit a job

Choose the language path and processing selectors before uploading. This example requests Arabic–English code-switching, speaker diarization, and inverse text normalization:

curl --fail-with-body --connect-timeout 10 --max-time 120 \
  -X POST "$API_URL/v1/transcribe/codeswitch?asr=bayan_cs_ar_en&diarization=1&itn=1&redact=0" \
  -H "x-api-key: $API_KEY" \
  -F "file=@meeting.wav"

A successful job creation returns HTTP 200. The validated specification includes this response:

{
  "jobId": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "status": "queued"
}

Check the HTTP status before parsing the success shape, then persist jobId with your application work item. It is the handle for subsequent result reads.

Processing selectors

SelectorLocationAccepted valuesEffect
langPathen, ar, codeswitch, autoSelects the transcription language workflow
asrQueryPublished model wire valueOverrides the model selected for the language
diarizationQuery0, 1, d1, d2Selects speaker diarization
itnQuery0, 1Enables inverse text normalization
redactQuery0, 1Enables redaction

Use the model map for published model wire values. Do not invent a model suffix that the map does not expose.

3. Poll the V2 result route with a deadline

Read the direct V2 result with the returned job UUID:

export JOB_ID="<jobId returned by the submission request>"
curl --fail-with-body --connect-timeout 10 --max-time 15 \
  "$API_URL/v1/transcribe/$JOB_ID?save_result=true" \
  -H "x-api-key: $API_KEY"

GET /v1/transcribe/{job_id} returns { "message": "success", "data": … }. Branch only on data.status:

StatusApplication action
queuedWait, then read again while the overall deadline remains
processingKeep waiting within the same deadline
doneStop polling and consume the completed result fields
failedStop polling and surface the job failure
clearedStop polling; the result is unavailable

Use this bounded polling sequence:

  1. Set one overall deadline before the first result read.
  2. Give every GET its own shorter request timeout.
  3. Accept only queued and processing as reasons to wait and poll again.
  4. Stop immediately for done, failed, or cleared.
  5. Stop locally when the overall deadline expires; don't infer a server-side terminal state from a client timeout.

Set save_result=true before the first poll when delivery of the terminal response must be repeatable. With the default false, a done or failed read can clear stored result fields after constructing its response. If that response is lost, the next read can return cleared instead of the result.

The polling interval and deadline are application choices, not service guarantees. The recording recipe provides bounded JavaScript and Python loops.

4. Keep V1 and V2 separate

RouteIntended useResponse shapeOptional result selectors
GET /v1/transcribe/{job_id}Direct V2 result readWrapper with data.final_result, data.final_word_segments, and data.diarization_segmentssave_result, default false
GET /v1/transcribe/{job_id}/{lang}Legacy V1 and SDK 0.18.0metadata, results.transcript, results.offsets, and diarization_segmentssave_result, default false; direct HTTP only: diarization_force_align, default true

Both shapes use the same five job statuses, but their field names and nesting differ. Do not mix V2 snake-case word segments with V1 offsets in one type. On either route, the default save_result=false can make a terminal done or failed response a single-consumption read. Set it to true before polling when a lost response must be retrievable again. The contract doesn't specify a result-retention duration, even with save_result=true; treat cleared as terminal without assuming recovery is possible.

The V1 lang segment is retained for compatibility but the current result handler does not use or validate it. SDK 0.18.0 sends the submission language; new direct HTTP clients should use V2.

5. Reconcile diarization

V2 final_word_segments do not contain speaker. When diarization is enabled, reconcile each word with diarization_segments using an application rule you document, such as assigning the segment that contains the word midpoint. Keep an unknown speaker when no segment overlaps unless your application explicitly adopts nearest-segment assignment.

The V1 route can place speaker on word offsets. Its direct-only diarization_force_align option changes those offset labels, not the raw diarization_segments; SDK 0.18.0 does not expose it. With the default true, a word whose startTime is outside every real segment uses the speaker at the nearest segment boundary, measured from the word midpoint; ties use the earlier segment. With false, it uses UNKNOWN_SPEAKER. With no real segments, the speaker stays null.

Speaker labels describe relative turns in one result; they do not establish a real-world identity.

6. Handle capacity and ambiguous retries

Batch submission can return HTTP 429 with structured error fields and the remaining capacity in audio seconds at data.capacity:

{
  "error": "error.rate_limit",
  "code": "RATE_LIMIT_EXCEEDED",
  "detail": "error.rate_limit",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": { "capacity": 120.5 }
}

For an explicit 429, queue or slow producers and retry with bounded attempts, backoff, and an overall deadline. Use capacity for admission decisions; the contract does not define it as a sleep duration.

A connection failure or timeout after an upload is different: the first request may already have created a job. The batch contract does not document an idempotency-key header, so do not blindly resubmit. Record the ambiguous attempt and retry only under an application policy that explicitly accepts the risk of a duplicate job. Result GETs can use bounded retries only when save_result=true was set before terminal retrieval; the default destructive read can become cleared after a lost response. See Errors and Rate Limits.

7. Continue to reference and production checks

Implement one representative recording first, then keep the generated Batch API reference beside your code for exact schemas. Before launch, exercise authentication failures, invalid audio, 429, polling deadlines, and all three terminal outcomes.

On this page