Subchapter 2.1
references/api-reference.mdMarkdown13 KBView on GitHub
Full endpoint-by-endpoint reference for the Dubbing Projects API.
https://api.elevenlabs.ioxi-api-key header on every request (the SDKs read ELEVENLABS_API_KEY)elevenlabs.dubbing.project.* in Python and JavaScript (camelCase methods in JS). The older client.dubbing.* methods are the legacy v1 API — do not use themdubbing_v2 (default)| Method | Path | Python SDK method | Purpose |
|---|---|---|---|
| POST | /v1/dubbing/project | dubbing.project.create | Create a project (file or URL) |
| GET | /v1/dubbing/project | dubbing.project.list | List projects (paginated) |
| GET | /v1/dubbing/project/{project_id} | dubbing.project.get | Get a project |
| DELETE | /v1/dubbing/project/{project_id} | dubbing.project.delete | Delete a project and its languages |
| GET | /v1/dubbing/project/{project_id}/transcript | dubbing.project.transcript.get | Get the source transcript |
| PATCH | /v1/dubbing/project/{project_id}/transcript/segment/{segment_id} | dubbing.project.transcript.update_segment | Edit a source segment |
| POST | /v1/dubbing/project/{project_id}/transcript/segment | dubbing.project.transcript.create_segment | Add a source segment |
| DELETE | /v1/dubbing/project/{project_id}/transcript/segment/{segment_id} | dubbing.project.transcript.delete_segment | Delete a source segment |
| POST | /v1/dubbing/project/{project_id}/language | dubbing.project.language.create | Add a language target |
| GET | /v1/dubbing/project/{project_id}/language | dubbing.project.language.list | List language targets (paginated) |
| GET | /v1/dubbing/project/{project_id}/language/{language_id} | dubbing.project.language.get | Get a language target |
| DELETE | /v1/dubbing/project/{project_id}/language/{language_id} | dubbing.project.language.delete | Delete a language target |
| GET | /v1/dubbing/project/{project_id}/language/{language_id}/transcript | dubbing.project.language.transcript.get | Get a language’s transcript (translations) |
| PATCH | /v1/dubbing/project/{project_id}/language/{language_id}/transcript/segment/{segment_id} | dubbing.project.language.transcript.update_segment | Edit a translation |
| POST | /v1/dubbing/project/{project_id}/language/{language_id}/transcript/regenerate | dubbing.project.language.transcript.regenerate | Regenerate a language from its edited transcript |
JS methods are the same paths in camelCase (e.g. dubbing.project.transcript.updateSegment).
POST /v1/dubbing/project — multipart/form-data with either file or source_url (not both).
| Field | Required | Notes |
|---|---|---|
file | one of file/source_url | The source media to dub (audio or video) |
source_url | one of file/source_url | Public URL to fetch the source media from |
source_language | no | ISO 639 code (e.g. en). Omit to auto-detect |
reference | no | Free-form label to identify the project on your end (max 500 chars) |
model_id | no | dubbing_v2 (default) |
target_language | no | Optionally queue the first language target at creation; add more with language.create |
keyterms | no | Terms to bias transcription/translation toward (e.g. product or brand names), up to 1000 terms; each at most 50 characters and 5 words; <>{}[]\ not allowed. In multipart, repeat the field once per term |
Auto-detected source language: if source_language is omitted, the project’s source_language stays null; the detected language is reported as the language field on the source transcript.
Response (201 Created) — the project starts in queued; media is null until preparation finishes:
{
"project_id": "proj_1601kwkyxp0hfzvtmyxwqxx6mcy3",
"status": "queued",
"reference": "Q3 marketing video",
"source_language": "en",
"model_id": "dubbing_v2",
"media": null,
"language_ids": [],
"revision": 0,
"created_at": "2026-07-03T10:15:30Z",
"updated_at": "2026-07-03T10:15:30Z"
}The source is fetched (for a URL) and transcribed asynchronously — poll the project until it reaches ready.
GET /v1/dubbing/project/{project_id}
Once ready, media is populated:
{
"project_id": "proj_1601kwkyxp0hfzvtmyxwqxx6mcy3",
"status": "ready",
"reference": "Q3 marketing video",
"source_language": "en",
"model_id": "dubbing_v2",
"media": {
"filename": "promo.mp4",
"duration_s": 42.5,
"has_video": true,
"mime_type": "video/mp4"
},
"language_ids": [],
"revision": 0,
"created_at": "2026-07-03T10:15:30Z",
"updated_at": "2026-07-03T10:17:12Z"
}language_ids stays empty until languages are added; revision stays 0 until the source transcript is edited (transcription itself doesn’t bump it).
Project states:
| Status | Meaning |
|---|---|
queued | Created; the source is being fetched and preparation is enqueued, but no worker has started it yet |
preparing | Preparation tasks are running |
ready | Preparation finished. The source transcript is available and languages can be added/generated. A project stays at ready — per-language progress lives on the languages |
failed | Preparation failed (e.g. the source couldn’t be fetched or decoded) |
GET /v1/dubbing/project — cursor-paginated.
Query params: page_size (default 20, max 100), cursor, status (queued/preparing/ready/failed), sort_direction (DESCENDING default).
{ "projects": [ /* ProjectResponse... */ ], "next_cursor": null }Pass next_cursor back as cursor to fetch the next page; null means the end.
DELETE /v1/dubbing/project/{project_id} — deletes the project and its languages.
Transcript editing (and regeneration) is available to enterprise workspaces only. Every source edit bumps the project’s revision; each edit response returns the new value. Editing the source after a language exists marks that language’s output stale and requires a regeneration — finalize the source before adding languages.
GET /v1/dubbing/project/{project_id}/transcript
{
"language": "en",
"segments": [
{
"id": "0199a3f0-1c2d-7abc-8def-0123456789ab",
"text": "Welcome to our product demo.",
"speaker_id": "default_speaker",
"start_s": 0.0,
"end_s": 2.5
}
],
"revision": 0
}Each segment has a stable id used to edit or delete it.
PATCH /v1/dubbing/project/{project_id}/transcript/segment/{segment_id}
Send only the fields to change (text, speaker_id, start_s, end_s); at least one is required. If sending both start_s and end_s, end_s must be greater than start_s.
{
"segment": {
"id": "0199a3f0-1c2d-7abc-8def-0123456789ab",
"text": "Welcome to our latest product demo.",
"speaker_id": "default_speaker",
"start_s": 0.0,
"end_s": 2.5
},
"revision": 1
}POST /v1/dubbing/project/{project_id}/transcript/segment
All fields required (text, speaker_id, start_s, end_s). The server assigns the segment id. Use a speaker_id that already appears in the source transcript so the new line is dubbed with that speaker’s voice.
The response echoes the new segment with its server-assigned id plus the new project revision.
DELETE /v1/dubbing/project/{project_id}/transcript/segment/{segment_id}
{ "revision": 3 }POST /v1/dubbing/project/{project_id}/language
JSON body:
| Field | Required | Notes |
|---|---|---|
target_language | yes | ISO 639 code (e.g. es) |
model_id | no | Defaults to the project’s model |
voice_settings | no | e.g. {"cloning_strength": 7} — cloning_strength accepts values between 0 and 10 inclusive (default 7); controls how strongly dubbed speakers clone the source voices |
Response (201 Created) — starts queued:
{
"language_id": "lang_1001kwkyxp0je6ktn4knsfrasx5s",
"project_id": "proj_1601kwkyxp0hfzvtmyxwqxx6mcy3",
"target_language": "es",
"status": "queued",
"model_id": "dubbing_v2",
"outputs": null,
"revision": 0,
"output_revision": null,
"created_at": "2026-07-03T10:16:00Z",
"updated_at": "2026-07-03T10:16:00Z"
}A language can be added to a project that isn’t ready yet — it stays queued and starts automatically once the project becomes ready. You can also queue the first language when creating the project by passing target_language to project.create.
Language states:
| Status | Meaning |
|---|---|
queued | Created and waiting — either on the project becoming ready, or on a worker to pick up its generation |
processing | The dub is being generated |
completed | The dub finished; outputs is populated |
stale | Previously completed, but its transcript (source or translation) changed, so the current output no longer matches. It keeps its last output until regenerated |
failed | Generation failed |
GET /v1/dubbing/project/{project_id}/language/{language_id}
Once completed, outputs carries a signed, time-limited download URL (valid ~1 hour; re-fetch the language for a fresh URL):
{
"language_id": "lang_1001kwkyxp0je6ktn4knsfrasx5s",
"project_id": "proj_1601kwkyxp0hfzvtmyxwqxx6mcy3",
"target_language": "es",
"status": "completed",
"model_id": "dubbing_v2",
"outputs": {
"lossless_audio": "https://storage.googleapis.com/eleven-dubbing/.../output.wav?X-Goog-Signature=..."
},
"revision": 0,
"output_revision": 0,
"created_at": "2026-07-03T10:16:00Z",
"updated_at": "2026-07-03T10:20:45Z"
}When output_revision equals revision, the downloadable output reflects the current transcript. When it’s behind (and status is stale), the output is out of date and needs a regeneration.
GET /v1/dubbing/project/{project_id}/language — cursor-paginated, optional status filter.
DELETE /v1/dubbing/project/{project_id}/language/{language_id} → 204 No Content.
GET /v1/dubbing/project/{project_id}/language/{language_id}/transcript
Pairs each source segment with its translation (null = not yet translated). Segment ids match the source transcript, so translations line up against the source.
{
"source_language": "en",
"target_language": "es",
"segments": [
{
"id": "0199a3f0-1c2d-7abc-8def-0123456789ab",
"speaker_id": "default_speaker",
"start_s": 0.0,
"end_s": 2.5,
"source_text": "Welcome to our latest product demo.",
"translation": "Bienvenido a la demostración de nuestro producto."
}
],
"revision": 0
}PATCH /v1/dubbing/project/{project_id}/language/{language_id}/transcript/segment/{segment_id}
Body: {"translation": "..."}. Pass null to clear it and mark the segment for re-translation.
A translation edit affects only this language — the source transcript and other languages are untouched. It bumps this language’s revision, and a completed language becomes stale: its downloadable output still reflects the previous output_revision until regenerated.
POST /v1/dubbing/project/{project_id}/language/{language_id}/transcript/regenerate
Produces a fresh dub from the current transcript after editing a language’s translation (or after source edits marked it stale). Charged like a generation.
Response (202 Accepted) — the language goes back to queued; output_revision still points at the previous output until the new one finishes:
{
"language_id": "lang_1001kwkyxp0je6ktn4knsfrasx5s",
"project_id": "proj_1601kwkyxp0hfzvtmyxwqxx6mcy3",
"target_language": "es",
"status": "queued",
"model_id": "dubbing_v2",
"outputs": null,
"revision": 1,
"output_revision": 0,
"created_at": "2026-07-03T10:16:00Z",
"updated_at": "2026-07-03T10:25:10Z"
}Poll the language until completed, then download the refreshed outputs.lossless_audio. At that point output_revision equals revision.
Returns 409 Conflict if the project isn’t ready or the language isn’t in a settled state (e.g. it’s already generating).
Every project and language carries its own monotonic revision counter, each starting at 0 and independent of the others:
revision increases on each source-transcript edit (transcription itself doesn’t bump it).revision starts at 0 when the language is created — it does not inherit the project’s current revision — and increases when its translation is edited or when a source edit affects it.output_revision is the revision its current audio was generated from. When output_revision is behind revision, the output is out of date and needs a regeneration.