Skip to main content
Preview. This API is a preview release and may be further refined before it is marked stable. See release stages for what that means.
You submit a list of synthesis requests, the server immediately returns a long-running operation, and the whole set is synthesized in the background. Poll the operation until it is done, then download a results file that names every item’s audio. Best for large libraries generated in one pass — every line of dialogue in a game, a catalogue of product descriptions, or re-recording an existing script after a voice change. Each item carries its own request, so a single batch can mix voices, models, languages, and audio formats freely.
For one long piece of text, use the Async API — batch is for many separate requests, not for splitting one. For a single request/response, use the Synthesize Speech API.

How it works

1

Submit the batch

POST /tts/v1/voice:synthesizeBatch with an items array. Each item pairs a customId of your choosing with a request identical in shape to synchronous synthesis. The response is an operation named workspaces/{workspace}/ttsBatchJobs/{batch}/operations/{operation} with done: false.
2

Poll the operation

GET /lro/v1alpha/{name} with the full operation name (including its slashes) in the URL path — the same endpoint async jobs use. Poll every few seconds; a large batch can take minutes.
3

Download the results file

When done is true, the response carries a resultsUri rather than per-item URLs — a batch’s results do not fit in one response. Fetch that file to get every item’s outcome, then fetch each item’s audioUri. All of these are pre-signed URLs: request them without an Authorization header. They expire at expireTime, approximately 7 days after completion.

Correlating results

customId is required, must be unique within the batch, and is the supported way to match a result back to what you submitted. Results also appear in submission order, but prefer the key — it stays correct if you ever submit in a different order than you read. Treat it as opaque: the service never interprets it, only echoes it back — in the results file, and in any error naming the item it belongs to. Keep it under 64 characters; longer ids are truncated where they are echoed into error messages.

When items fail

A batch is rejected as a whole, at submit, if any item is invalid — an unknown voice, an unsupported model, text past the ceiling. The error names the offending item by both of your handles on it, for example items[1] (custom_id "chapter-02"): Unknown voice: Nope not found!. Nothing is synthesized and no job is created, so fix the item and resubmit. Once a batch is running, the rule inverts: an item that fails during synthesis gets an error in its results entry instead of an audioUri, and the rest of the batch still completes. Check failedItems and the per-item error field rather than assuming every entry has audio.
failedItems is omitted from the results file rather than sent as 0 when every item succeeds, so read it with a default (results.get("failedItems", 0)) rather than testing whether the key is present. The same applies to any zero-valued field in these responses.

Items that request timestamps

An item that sets timestampType needs alignment to succeed as well as synthesis. If alignment cannot be produced, the item fails outright — batch never returns audio with the timestamps quietly missing, because an item that asked for timing and got none is not the result that was asked for. Timestamp availability is tracked separately from synthesis, so a language can in principle synthesize while alignment for it is unavailable. Wherever that is true you find out at submit — never after paying for audio you cannot use due to the lack of timestamps. Such an item is rejected before any job exists and, like every other invalid item, takes the whole batch with it:
No job is created and nothing is charged. The error names both the item and the language, so you do not need to check anything in advance: if a batch is accepted, timestamps are available for every item in it. Fix the named item and resubmit. An item that passes submit can still fail during synthesis. Two outcomes are worth telling apart, because only one is worth retrying:
The synchronous and streaming endpoints behave the opposite way: they keep the audio and return success with no timestampInfo at all. Only async and batch jobs turn a timestamp failure into a failure of the request. If you are porting code from those endpoints, an item error where you previously saw silently missing timestamps is expected.

Limits

Submissions over either per-account limit are rejected with a RESOURCE_EXHAUSTED error and create nothing — no operation, and no partial synthesis. Retry once earlier batches finish. Because a batch holds up to 10,000 items, prefer packing work into one batch over submitting many small ones; see Pack items into one batch.
Persist the operation name from every submit response. If you lose one, list operations across all of your batch jobs — GET /lro/v1alpha/ttsBatchJobs/-/operations, optionally with filter=-done for running batches only. See Listing your jobs for the full contract.

API Reference

Synthesize Speech (Batch)

Submit a batch synthesis job

Get Async Operation

Poll a job’s operation until it completes

List Batch Operations

List your batch jobs across the workspace

Next Steps

Synthesize Speech (Async)

Submit a single long-form job instead of many separate ones.

Timestamps

Get word or character timing alignment alongside your audio.

Speech Generation Best Practices

Learn best practices for synthesizing high-quality speech.