Batch API

Submit a transcription job

Submit one complete recording for asynchronous Batch transcription.

POST/transcribe/{lang}

Submit one complete recording for asynchronous Batch transcription. Use Batch for long or large complete media; use Fast for one complete, bounded, latency-sensitive conversational unit, and Realtime only while audio is still arriving.

A 200 response means the job was accepted with status queued, not that transcription finished. Persist jobId, then poll GET /transcribe/{job_id} until done, failed, or cleared.

This operation has no idempotency-key contract. Do not blindly replay an upload after a timeout, connection loss, or 5xx: the job may already exist and a replay can create duplicate work. A 429 response is capacity backpressure; data.capacity is remaining audio capacity in seconds when a balance is available, not a delay or reset time.

Authorization

ApiKeyAuth
x-api-key<token>

In: header

Path Parameters

lang*string

Language code for transcription.

Query Parameters

asr?string

Optional exact ASR model key. When omitted, the service uses the configured default for the selected lang. An unknown key or a missing configured default returns 400 with ASR_MODEL_NOT_FOUND.

diarization?string

Speaker diarization selector:

  • omitted, 0, or false: Disabled
  • 1 or true: Enabled with default model
  • d1: Speaker diarization
  • d2: Speaker diarization (alternative)
itn?string

Inverse Text Normalization (ITN) selector:

  • omitted, 0, or false: Disabled
  • 1 or true: Enabled (converts spoken forms to written, e.g., "twenty five" → "25")
redact?string

PII Redaction selector:

  • omitted, 0, or false: Disabled
  • 1 or true: Enabled (masks sensitive information in transcripts)

Request Body

multipart/form-data

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

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/transcribe/en?diarization=1&itn=1&redact=1" \  -H "Origin: https://example.com" \  -F "file=@meeting.wav"

Job accepted and queued for asynchronous processing

application/json

Example queued

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

Invalid language, model, content type, multipart body, or file field

application/json

Invalid language

{
  "error": "error.language.invalid",
  "code": "VALIDATION_INVALID_LANGUAGE",
  "detail": "error.language.invalid",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Request is not multipart form data

{
  "error": "error.api.error.request.invalid_format",
  "code": "VALIDATION_INVALID_FORMAT",
  "detail": "error.api.error.request.invalid_format",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

First multipart field is not file

{
  "error": "error.api.error.multipart.file.missing",
  "code": "VALIDATION_REQUIRED_FIELD",
  "detail": "error.api.error.multipart.file.missing",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

ASR model is not configured

{
  "error": "error.asr_model.not_found",
  "code": "ASR_MODEL_NOT_FOUND",
  "detail": "error.asr_model.not_found",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Unauthorized

application/json

Example missing_key

{
  "error": "auth.unauthorized",
  "message": "unauthorized",
  "code": "AUTH_UNAUTHORIZED",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

The API key does not grant batch transcription access

application/json

Example scope_denied

{
  "error": "error.api_key.scope_denied",
  "code": "AUTH_FORBIDDEN",
  "detail": "scope not permitted",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

The request exceeded the byte limit. No job was created and no transcription was started. data.observed is the client's declared Content-Length when it already exceeded the limit; when the body was rejected while being read it is limit + 1, the smallest provable size, because reading stops there.

application/json

Content-Length already exceeds the limit

{
  "error": "error.api.error.request.too_large",
  "code": "PAYLOAD_TOO_LARGE",
  "detail": "error.api.error.request.too_large",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "request_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "data": {
    "limit": 536870912,
    "observed": 1073741824,
    "unit": "bytes",
    "bound": "request_bytes"
  }
}

Too much data beyond the recording to finish checking the limits

{
  "error": "error.api.error.request.unvalidatable_tail",
  "code": "PAYLOAD_TOO_LARGE",
  "detail": "error.api.error.request.unvalidatable_tail",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 524288,
    "observed": 524289,
    "unit": "bytes",
    "bound": "unvalidatable_tail_bytes"
  }
}

Body overran the limit mid-stream

{
  "error": "error.api.error.request.too_large",
  "code": "PAYLOAD_TOO_LARGE",
  "detail": "error.api.error.request.too_large",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 536870912,
    "observed": 536870913,
    "unit": "bytes",
    "bound": "request_bytes"
  }
}

Unsupported or corrupt audio input, or a valid request whose workload exceeds a semantic limit. No job was created and no transcription was started; see "Request limits" for when audio is converted before the rejection.

application/json

Example unsupported_audio

{
  "error": "unsupported or corrupt audio input for conversion",
  "code": "VALIDATION_FILE_CORRUPT",
  "detail": "unsupported or corrupt audio input for conversion",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Decoded audio exceeds the duration limit

{
  "error": "error.api.error.audio.duration_exceeded",
  "code": "AUDIO_DURATION_EXCEEDED",
  "detail": "error.api.error.audio.duration_exceeded",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "request_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "data": {
    "limit": 14400,
    "observed": 21600,
    "unit": "seconds",
    "bound": "audio_duration"
  }
}

More than one audio part was submitted

{
  "error": "error.api.error.multipart.file.count_exceeded",
  "code": "FILE_COUNT_EXCEEDED",
  "detail": "error.api.error.multipart.file.count_exceeded",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 1,
    "observed": 2,
    "unit": "files",
    "bound": "file_parts"
  }
}

More multipart parts than the request allows

{
  "error": "error.api.error.multipart.part.count_exceeded",
  "code": "FILE_COUNT_EXCEEDED",
  "detail": "error.api.error.multipart.part.count_exceeded",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 8,
    "observed": 9,
    "unit": "parts",
    "bound": "multipart_parts"
  }
}

Audio capacity is exhausted. data.capacity is remaining audio seconds when a balance is available; it is not a retry delay, reset timestamp, or quota guarantee. A zero value can mean no balance was available.

application/json

Example limited

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

Submission failed; the outcome can be ambiguous after job creation

application/json

Example transcription_failed

{
  "error": "error.api.transcription",
  "code": "ASR_TRANSCRIPTION_FAILED",
  "detail": "error.api.transcription",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z"
}

Next steps

Once the request returns a jobId, persist it before leaving your request handler. Then poll the V2 lookup with a bounded deadline until the job reaches done, failed, or cleared.

On this page