Batch mode provides asynchronous transcription for large or complex jobs that require processing multiple files or lengthy recordings.
Capabilities
- Parallel file processing
- Asynchronous operation
- Large-scale recording support
- Multi-speaker and multi-channel audio support
- Language detection, model selection, custom vocabulary, and Text Polishing (
en-USonly, without language detection)
Each audio file generates its own transcript that saves to a corresponding output location.
How it works
Batch mode processing runs asynchronously and enables you to transcribe multiple files in a single API call.
This mode is ideal for workflows that involve large file collections.
Input
The API supports three input modes.
| Mode | Description |
|---|---|
SINGLE | A single audio file. Inferred when the URI points to a single file. |
PREFIX | All files under a shared S3 prefix/container. Supports glob filters to include or exclude files. |
MANIFEST | An explicit list of file URIs. Maximum 1,000 files per manifest. |
Output
The API supports three output layouts.
| Layout | Description |
|---|---|
SINGLE | Use the output URI as a single transcript file path. Valid only with SINGLE input. The uri can be a pre-signed HTTPS URL, in which case auth isn't needed. |
ADJACENT | Place each transcript next to its input file (same directory). Valid only with PREFIX input. No output uri is needed, but destination is required. |
PREFIX | Use the output URI as the base directory for all transcripts. Required for MANIFEST input. |
With PREFIX and ADJACENT layouts, each transcript is named after its input file with a unique suffix, such as a1.wav_8931d872-85bd-4fdf-b133-822c4090e008.json. With the SINGLE layout, the transcript is written to the exact output uri.
Audio requirements
- Formats: WAV, MP3, M4A, MP4, and WebM
- Channels: Mono or stereo
- Sample rate: At least 8 kHz; 16 kHz or greater is recommended
- Maximum duration per file: 2 hours
- Maximum size per file: 300 MB
Transcription options
These options control recognition. For full descriptions, see Speech configuration.
| Parameter | Type | Default | Description |
|---|---|---|---|
language | string | en-US | Language code, such as en-US. See Speech configuration for supported languages. |
segmentation_mode | string | "auto" | Voice Activity Detection (VAD) mode. Set "none" to disable. |
word_time_offsets | boolean | false | Include word-level timestamps. |
channel_separation | boolean | false | Transcribe stereo channels separately. |
diarization | boolean | false | Identify speakers and add a speaker tag to each transcript segment. |
model | string | Automatic | Select a compatible recognition model. |
language_detection | object | — | Detect each file's language once or continuously. Omit model when mode is once. |
profanity_filter | boolean | false | Filter profanity when supported by the selected model. |
text_polishing | object | — | Whether to return polished text. enabled boolean defaults to false. See Text Polishing. |
vocabulary | object | — | Apply an inline phrase list to every file in the job. |
vocabulary_id | string | — | Apply a persistent Vocabulary Asset. |
For model and language options, see Speech configuration. For vocabulary options, see Custom vocabulary.
Batch jobs
Create a batch job
To create a new batch transcription job, use this endpoint:
POST /aiservices/scribe/jobs
You can optionally include a reference_id for tracking.
To receive webhook notifications when a job finishes, include a notifications object with a webhook_url and a secret for payload verification.
Example request (cURL)
This cURL example submits a batch transcription job from S3 and defines the output location and settings. The response returns a job ID and status so you can track processing.
curl -X POST https://api.zoom.us/v2/aiservices/scribe/jobs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"input": {
"mode": "PREFIX",
"source": "S3",
"uri": "s3://acme-bucket/audio/2026/10/",
"filters": {
"include_globs": ["**/*.wav", "**/*.mp3"],
"exclude_globs": ["**/tmp/**"]
},
"auth": {
"aws": {
"access_key_id": "AKIA...",
"secret_access_key": "wJalrX...",
"session_token": "FwoGZXIvYXdzE..."
}
}
},
"output": {
"destination": "S3",
"uri": "s3://acme-bucket/transcripts/2026/10/",
"layout": "PREFIX",
"auth": {
"aws": {
"access_key_id": "AKIA...",
"secret_access_key": "wJalrX...",
"session_token": "FwoGZXIvYXdzE..."
}
}
},
"config": {
"language": "en-US",
"model": "zoom-scribe-en",
"word_time_offsets": true,
"channel_separation": false,
"diarization": false
},
"outputs": {
"text_polishing": {
"enabled": true
}
},
"notifications": {
"webhook_url": "https://example.com/hooks/scribe",
"secret": "hmac-secret"
},
"reference_id": "import-2025-11"
}'
Use temporary AWS STS credentials in auth.aws, including session_token.
Each completed output file contains the original transcript. When Text Polishing is enabled, the file also contains outputs.text_polishing.text. See Text Polishing.
Response (201)
{
"job_id": "8e5a1f3c-2d7b-4c9e-a6f1-0b4d7e2c9a58",
"state": "QUEUED",
"submitted_at": "2026-01-05T18:34:12Z"
}
Batch job endpoints
Five additional endpoints are available to manage batch jobs.
| Action | Description | Endpoint |
|---|---|---|
| Get batch job status | Check the current status and progress summary of a specific job. | GET /aiservices/scribe/jobs/{jobId} |
| List batch jobs | View all batch jobs, optionally filtered by state. | GET /aiservices/scribe/jobs?state=QUEUED&page_size=50&next_page_token=... |
| Cancel batch job | Cancel a job that is in QUEUED or PROCESSING state. | DELETE /aiservices/scribe/jobs/{jobId} |
| List batch job files | Retrieve per-file status with pagination. | GET /aiservices/scribe/jobs/{jobId}/files?page_size=200&next_page_token=... |
| Get batch job file | Retrieve the status and output location of an individual file. | GET /aiservices/scribe/jobs/{jobId}/files/{fileId} |
List responses include a next_cursor field. Pass its value as the next_page_token query parameter to retrieve the next page.
Job and file states
Files in a job are processed independently. If any file fails or is skipped while others succeed, the job ends in PARTIAL. The job status response includes a summary with counts for total_files, queued, processing, succeeded, failed, skipped, and canceled.
| Job state | Description |
|---|---|
QUEUED | The job is waiting to start. |
PROCESSING | Files are being transcribed. |
SUCCEEDED | All files were transcribed. |
PARTIAL | Some files were transcribed, and some failed or were skipped. |
FAILED | The job failed. |
CANCELED | The job was canceled. This is a terminal state. |
| File state | Description |
|---|---|
FILE_QUEUED | The file is waiting to be processed. |
FILE_PROCESSING | The file is being transcribed. |
FILE_SUCCEEDED | The transcript was written to the output location. |
FILE_FAILED | The file couldn't be transcribed. |
FILE_CANCELED | Processing was canceled for the file. |
FILE_SKIPPED | The file was skipped because its extension isn't supported. The file's error.code is UNSUPPORTED_MEDIA. |
Webhook verification
When you provide a secret in the notifications object, the API signs each webhook request so you can verify that Zoom AI Services sent it.
Each webhook request includes two headers.
| Header | Description |
|---|---|
x-zm-signature | HMAC-SHA256 signature of the request, prefixed with sha256= |
x-zm-request-timestamp | Unix timestamp of when the request was sent |
To verify the signature:
- Compute the
HMAC-SHA256of the stringv0:{timestamp}:{raw_body}using your secret key - Compare it with the value in
x-zm-signatureusing a timing-safe comparison to prevent timing attacks. - Reject the request if the signatures do not match or if the timestamp is stale.
const message = `v0:${timestamp}:${rawBody}`;
const expected = `sha256=${crypto.createHmac('sha256', secret).update(message).digest('hex')}`;
const a = Buffer.from(signature);
const b = Buffer.from(expected);
const isValid = a.length === b.length && crypto.timingSafeEqual(a, b);