Batch Processing
The Sync Labs Batch API processes up to 500 lip sync generations in a single request, sent as a JSONL file or as a JSON array of rows. This is ideal for bulk video processing workflows, such as personalized video campaigns, content localization, or any scenario requiring high-volume lip sync generation.
What is the batch file format?
Batch processing enables you to submit 20 to 500 generations without having to handle queueing or concurrency yourself, with a target turnaround time of 24 hours. Batch jobs bypass your normal generation concurrency limit, but the Batch API is only available on the Scale plan or higher. As of now, only generations with inputs up to 30 seconds are supported in batch processing.
Batch API requires the Scale plan or higher, including Enterprise
Batch concurrency limits
Batch jobs bypass your normal per-generation concurrency limit, but a separate limit caps how many batches you can run at once, based on your plan. If you submit a new batch while you are already at that limit, the API returns a 429 Too Many Requests response.
The 429 body is a JSON object describing the limit you hit:
The response also includes a Retry-After header (in seconds) and an X-Sync-Concurrency-Limit header. Rather than retrying immediately, wait retryAfterSeconds before submitting again, or wait for one of your in-flight batches to complete.
How do I create a batch job?
Prepare Your Input File
Create a JSON Lines (.jsonl) file with your generation requests. Each line should contain a unique request_id, the endpoint (must be "/v2/generate"), and a payload with the standard generation request format (same as the Generate API). The file must be in JSON Lines (.jsonl) format with a minimum of 20 records, maximum file size of 5MB, and up to 500 requests per batch.
Create a Batch
Instead of uploading a file, you can send application/json with the records in rows. Each row is the same object as one JSONL line, and both forms are validated the same way: 20 to 500 rows by default, 5 MB or smaller when written as JSONL, and unique request_id values. When a record is refused, the error names its line. Dialogue edit refusals return it in a lineNumber field; other record errors, such as invalid JSON or a missing request_id, give it only in message (for example Record at line 4: payload is required). Lines count non-empty records, not physical lines, so blank lines in a JSONL file are skipped; with a JSON body, line N is rows[N-1]. The examples above show two records for brevity; a batch needs at least 20.
Optional parameters:
webhook_url: Receive notifications when the batch completesdry_run: Set totrueto validate your input without processing. A valid input returns{"status": "VALIDATED"}and creates no batch.
Batch creation is not covered by idempotent requests. If a create request times out, list your batches with GET /v2/batch before submitting again, so you do not run the same rows twice.
Check Batch Status
Monitor your batch progress by polling the status:
A batch can have one of the following status:
PENDING: Batch created, waiting to start processingPROCESSING: Generations are being processedCOMPLETED: All generations finished (successfully or with failures)FAILED: Batch processing failed entirely
Check Batch Results
When a batch completes, results are available as a JSON Lines file at the outputUrl of the get batch response. A GET to that URL returns a 302 redirect to a signed result file; clients that follow redirects automatically can read the JSONL response directly. Each line contains:
The response field contains the same data as individual Generate API responses. Field names in the results file are snake_case, so a completed row’s video is at response.output_url and its generation ID at response.id. Match each line to your input by request_id.
For a complete working example, see the batch processing example in our examples repository.
Webhook Notifications
When you provide a webhook_url, you’ll receive POST notifications when your batch completes:
Batch webhook delivery is retried until delivered. Your receiver should treat the batch ID as an idempotency key and safely ignore duplicate notifications.
The completion webhook can be delivered more than once for the same batch. Use the batch id to ignore notifications you have already processed.
Dialogue edit rows (early access)
A batch row can render a completed dialogue edit preview instead of pairing a video with new audio. Use this to turn one recorded video into many variants, such as one per recipient name. Personalized Video Messaging has a complete script.
Dialogue edit rows are in early access and are enabled per organization. Contact us to turn them on. Until then, rows that carry dialogueEdit are refused at submit.
Each row’s payload contains:
model, for examplesync-3.inputwith exactly one video: the same source video the preview was made from.dialogueEdit: {"id": "..."}: the ID of a completed preview fromPOST /v2/dialogue-editsin your organization.
Do not add audio or text inputs, segments, or dubParams; the preview supplies the audio.
The same row objects work as lines in a JSONL file upload.
At submit, each dialogue edit row is expanded into exactly the request POST /v2/generate builds for that preview, and it is charged the same as that generation. The payload in the results file shows the expanded request (the video, the preview audio, and the edited segments), not the row you sent. Send the batch with dry_run: true first: it runs every check below, including the expansion, without rendering anything.
- All dialogue edit rows in one batch must use previews made from the same source video. For several videos, submit one batch per video.
- The usual batch limits apply: 20 to 500 rows and 5 MB.
- Most previews render as edited segments of the video. A preview that can only be rendered as whole-video lip sync is accepted in a batch only when that render is 30 seconds or shorter; render longer ones with
POST /v2/generate.
Dialogue edit refusals
If any dialogue edit row cannot be rendered, the whole request is refused and no batch is created. The response carries the errorCode that POST /v2/generate would return for that preview, plus the lineNumber of the first failing row:
Only the first failing row is reported. Fix it and repeat the dry run until it returns {"status": "VALIDATED"}.
Related Resources
- Rate Limits — understand API rate limiting to plan your batch sizes effectively
- Webhooks Guide — set up webhook notifications for batch completion events
- Error Handling — reference for batch-specific error codes and troubleshooting

