> For the documentation index, fetch https://sync.so/docs/llms.txt. Append .md to a page URL for Markdown. Documentation-search MCP: https://sync.so/docs/_mcp/server. # Asynchronous Text-to-Speech > Submit durable speech synthesis jobs, poll their results, and retry safely. Use `POST /v2/tts/jobs` to submit speech synthesis and retrieve the result later. Submission returns `202` with a job and a `Location` header. This is useful when your application needs to keep a job ID across a disconnect or restart. > **Note** > > API-key access requires your organization to be enabled for the asynchronous TTS rollout. A request from an organization without access returns `503`. The existing [`POST /v2/tts`](/developer-guides/text-to-speech) remains available with its synchronous `200` response containing `id`, `url`, and `duration`. ## Submit a job The body is the same as synchronous TTS: `script` contains 1–5,000 characters, `voiceId` identifies an available voice, and `provider` is required. Use `elevenlabs` for ElevenLabs voices. Optional `stability` and `similarityBoost` range from 0 to 1. ```bash curl -i https://api.sync.so/v2/tts/jobs \ -H "x-api-key: $SYNC_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: narration-take-001' \ -d '{ "script": "Welcome to our product tour.", "voiceId": "EXAVITQu4vr4xnSDxMaL", "provider": "elevenlabs" }' ``` Save the returned `id` before polling. A new job can look like this: ```json { "id": "6533643b-aceb-4c40-967e-d9ba9baac39e", "status": "PENDING", "url": null, "duration": null, "error": null, "createdAt": "2026-10-02T09:30:00Z", "startedAt": null, "finishedAt": null } ``` The response also sets `Location: /v2/tts/jobs/6533643b-aceb-4c40-967e-d9ba9baac39e`. An idempotent replay returns the original job in its current state, which may already be terminal. ## Poll and use the audio ```bash curl -i https://api.sync.so/v2/tts/jobs/6533643b-aceb-4c40-967e-d9ba9baac39e \ -H "x-api-key: $SYNC_API_KEY" ``` | Status | Action | | ------------ | --------------------------------------------------------------------------------------- | | `PENDING` | Keep the ID and wait before polling again. | | `PROCESSING` | Synthesis is running; keep polling. | | `SUCCESS` | Use `url` for hosted audio and `duration` for its length in seconds. | | `FAILED` | Inspect `error.code` and `error.message` before deciding whether to submit another job. | A pending or processing response includes `Retry-After: 3`. Wait at least three seconds before the next poll. Stop polling at `SUCCESS` or `FAILED`; terminal responses omit that header. Jobs are scoped to your organization, and a missing or inaccessible job returns `404`. On success, pass the returned `url` as an `audio` input to [`POST /v2/generate`](/api-reference/api/generate-api/create), alongside your video. This reuses the synthesized take; it does not synthesize the script again. ## Retries and errors Use one `Idempotency-Key` for each intended take. Keys contain 1–128 characters after trimming and are scoped to your organization. If submission times out or the response is lost, resend the same body and key. It returns the original job. Reusing the key with a different body returns `409`. An idempotent replay does not restart a failed job. After inspecting and correcting a failure, use a new key only when you intend a new synthesis attempt. In particular, `PROVIDER_RESULT_UNKNOWN` means the provider outcome was uncertain; do not assume a new submission is a free replay. | HTTP status at submission | Handling | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `400` | Correct the script, voice/provider fields, options, or idempotency key. | | `402` | Resolve the applicable billing or free-tier usage limit. | | `409` | Reuse the original body with the original key, or choose a new key for a different take. | | `422` | Check voice availability and restrictions. | | `503` | Check rollout access or temporary admission availability. Honor `Retry-After` when present and use backoff for temporary failures. | Accepted jobs report failures in `error`, separately from submission HTTP errors. Codes are `CREATE_FAILED`, `PROVIDER_FAILED`, `PROVIDER_TIMEOUT`, `PROVIDER_RESULT_UNKNOWN`, `UPLOAD_FAILED`, `TIMEOUT`, and `UNKNOWN`. Keep the job ID and error message for support. See [Error Handling](/developer-guides/error-handling) for shared billing and provider errors. > Submit durable speech synthesis jobs, poll their results, and retry safely.