POST
/v1/dubbing/project
ElevenLabs APICreate Dubbing Project
- Base URL
- https://api.elevenlabs.io
- Auth
- xi-api-key: <ELEVENLABS_API_KEY>
- Last verified
- 2026-09-03 · upstream hash matched
Actions
Agents: curl -H "Accept: text/markdown" this URL
→ 214 tokens · Vary: Accept
→ 214 tokens · Vary: Accept
Critical gotchas
Authentication uses the non-standard xi-api-key header, not Authorization: Bearer. Sending a Bearer token returns HTTP 401.
Text-to-speech responses are raw binary audio, not JSON. Write the body to a file (--output speech.mp3) rather than parsing it.
cURL
curl -X POST 'https://api.elevenlabs.io/v1/dubbing/project' \ -H "xi-api-key: $ELEVENLABS_API_KEY" \ -F 'file=@sample.bin' \ -F 'source_url=string' \ -F 'reference=string' \ -F 'source_language=string' \ -F 'model_id=dubbing_v1' \ -F 'keyterms=string' \ -F 'webhook_ids=string' \ -F 'target_language=string' \ -F 'transcript=@sample.bin'Get a free ElevenLabs API key → sponsored
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| file | body | string | No | The source media file to dub: an audio or video file of at most 3 GiB. Provide this or `source_url`, not both. |
| source_url | body | string | No | Public HTTP(S) URL the source media is fetched from server-side, subject to the same size and format limits as an upload. Provide this or `file`, not both. |
| reference | body | string | No | Optional free-form string (at most 500 characters) to identify the project on your end. Stored and echoed back verbatim; it does not affect the dub. |
| source_language | body | string | No | BCP-47 language tag of the source media; must be a language the transcription model supports. Any region or script subtag is ignored, since transcription is per-language. Omit to auto-detect. |
| model_id | body | string | No | Dubbing model (`dubbing_v1` or `dubbing_v2`) every language target of this project is dubbed with. Defaults to `dubbing_v2`. Fixed at create time — the source is prepared for this model, so neither the project nor an individual target can change it later. |
| keyterms | body | string[] | No | Key terms to bias transcription and translation toward (for example, product or brand names). At most 1,000 terms; each term at most 50 characters and 5 words; the characters `<>{}[]\` are not allowed. Terms are trimmed and deduplicated. |
| webhook_ids | body | string[] | No | IDs of workspace webhooks to notify as this project progresses — the alternative to polling, and what we recommend. Each receives a `dubbing_project_ready` or `dubbing_project_failed` event for the project, and a `dubbing_language_completed` or `dubbing_language_failed` event for every language under it; `dubbing_language_completed` carries the output download URLs. At most 3 IDs, each already configured in your workspace — see [Webhooks](https://elevenlabs.io/docs/eleven-api/resources/webhooks) for how to create one and verify its signature. Delivery is best-effort and can repeat, so we recommend handling events idempotently. |
| target_language | body | string | No | Optional shortcut: also create a language target in this BCP-47 language, queued to start once the project is ready — equivalent to creating the project and then creating one language target. Must be one of the [languages the dubbing model supports](https://elevenlabs.io/docs/help-center/product/dubbing/which-languages-are-supported-in-dubbing), and a region-qualified tag must be one of the supported dialects. This is the first language target, so it consumes the project's minimum charge rather than adding to it. Its ID is returned in `language_ids`. |
| transcript | body | string | No | Enterprise only. Optional JSON transcript to use instead of transcribing the source: a `{"segments": [...]}` document, at most 20,000 segments and 4 MiB. See [Bring your own transcript](https://elevenlabs.io/docs/eleven-api/guides/how-to/dubbing/bring-your-own-transcript) for the segment fields and their constraints. `source_language` is required whenever a transcript is provided. If any segment carries a `translation`, `target_language` is required and every segment must carry one; those translations seed the target created via `target_language`, which then skips machine translation. |
Response 200 OK
{
"project_id": "string",
"status": "queued",
"reference": "string",
"source_language": "string",
"model_id": "string",
"media": {
"filename": "string",
"duration_s": 0,
"has_video": true,
"mime_type": "string"
},
"language_ids": [],
"webhook_ids": [],
"revision": 0,
"error": {
"code": "string",
"message": "string",
"retryable": true
},
"warnings": [
{
"type": "string",
"speaker_ids": [
"string"
],
"message": "string"
}
],
"created_at": "2026-09-03T00:00:00Z",
"updated_at": "2026-09-03T00:00:00Z"
}