# ElevenLabs Dubbing (dub) > ElevenLabs Dubbing re-voices a finished video in another language and keeps the speaker's own voice. It is the cheapest dub model, and the only one whose price you know exactly before you run it. Status: roasOS API v1.1. Catalog `model-catalog@2026-10-06.v5`, pricing `customer-pricing@2026-11-05.v15`. The endpoint `POST /v1/dub/elevenlabs-dubbing` is live. `POST /v1/generations` has no `dub` type, so this endpoint is the only path to this model. ## Endpoint POST https://api.roasos.com/v1/dub/elevenlabs-dubbing Auth: Authorization: Bearer roasos_sk_… (scope api:write). Idempotency-Key required. quote_only / quote_id / webhook_url as in https://docs.roasos.com/llms.txt. ## Good at Take an ad that works in one market into a second market. Send the clip and a two-letter language code; the model detects the speakers and the source language on its own. Use it when the voice matters more than the mouth: it translates the audio and does not change the lips. The price is $0.6 for each minute of the SOURCE clip, rounded up to a whole minute. A 61-second clip costs two minutes, not 1.02. The quote is therefore exact, and settlement equals it. ## Pricing Unit: source_second. Pricing key: `elevenlabs-dubbing`. | request | credits | |---|---| | `30s_source` | 8 | | `60s_source` | 8 | | `120s_source` | 15 | Credits come from the roasOS pricing table (`MODEL_COSTS`) through the catalog. No other field changes the price. ## Modes - `video-dub` Provider endpoints: `fal-ai/elevenlabs/dubbing`. ## Request fields | field | type | required | default | rule | |---|---|---|---|---| | `highest_resolution` | boolean | no | `true` | — | | `language` | string | yes | — | matches `^[a-z]{2}$` | | `quote_id` | string | no | — | UUID | | `quote_only` | boolean | no | `false` | — | | `source_language` | string | no | — | matches `^[a-z]{2}$` | | `speaker_count` | integer | no | — | 1–50 | | `video_url` | string | yes | — | https URL; ≤ 4,096 characters | | `wait_timeout_seconds` | integer | no | `0` | 0–60 | | `webhook_url` | string | no | — | https URL; ≤ 4,096 characters | The schema is strict: a field that is not in this table returns `400 unsupported_option`. Field names are the roasOS role names, one name per role across every family. ## Media - `video_url` — the source video | role | items | max size | content types | duration | |---|---|---|---|---| | `video_url` | ≤ 1 | 100 MB | `video/mp4` | 0–480 s | - Refused: `avatar_id`, `elements`, `product_id`, `product_images`, `references`, `reference_images`, `image_url`, `end_image_url`, `scene_id`, `scene_image`, `video_urls`, `audio_urls`, `audio_url`, `voice_id`. A refused role returns `400 unsupported_option`. - Every URL must be an immutable object on `https://cdn.roasos.com/…` that your workspace owns; any other URL is `400 reference_media_not_workspace_owned`. Upload with `POST /v1/uploads` (direct POST of the bytes to `put_url`, or a `source_url` import), then use the returned CDN URL. ## Prompt None. This model takes no prompt. Send `language` as an ISO 639-1 code, in lower case: `es`, `fr`, `de`, `ja`, `pt`, `zh`. Leave `source_language` out unless the source is hard to detect. Leave `speaker_count` out unless the model splits one speaker into two, or joins two into one. ## Not exposed - `audio_url`: not accepted by this public endpoint. ## Result Result kind `video`. Always present: `url`. ```json { "data": { "id": "gen_…", "kind": "video", "model": "elevenlabs-dubbing", "status": "completed", "result": {"url":"https://cdn.roasos.com/workspaces/ws_01/result"} } } ``` Files live on `https://cdn.roasos.com` and are immutable; a result URL can be a media input to the next call. Poll `GET /v1/jobs/{id}/status` → `{ id, status, updated_at }`, then `GET /v1/jobs/{id}/result` (`409 run_not_completed` until the job is `completed`, `failed` or `canceled`). Statuses: `queued → processing → completed | failed | canceled`. ## Example ```bash # 1. quote — nothing is spent curl -X POST https://api.roasos.com/v1/dub/elevenlabs-dubbing \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-elevenlabs-dubbing-0001" \ -H "Content-Type: application/json" \ -d '{"quote_only":true,"language":"es","video_url":"https://cdn.roasos.com/workspaces/ws_01/uploads/video_url.mp4"}' # → 200 { "data": { "kind": "quote", "quote_id": "q_7Hk…", "credits": 8, "expires_at": "…", "confirmation": { "model": "elevenlabs-dubbing", "example": "30s_source" } } } # 2. run — the same body and the same Idempotency-Key, quote_id instead of quote_only curl -X POST https://api.roasos.com/v1/dub/elevenlabs-dubbing \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-elevenlabs-dubbing-0001" \ -H "Content-Type: application/json" \ -d '{"quote_id":"q_7Hk…","language":"es","video_url":"https://cdn.roasos.com/workspaces/ws_01/uploads/video_url.mp4"}' # → 201 { "data": { "id": "gen_…", "kind": "video", "model": "elevenlabs-dubbing", "status": "queued", "credits_reserved": 8, "links": { "status": "/v1/jobs/gen_…/status", "result": "/v1/jobs/gen_…/result" } } } # 3. poll curl https://api.roasos.com/v1/jobs/gen_…/status -H "Authorization: Bearer roasos_sk_live_…" curl https://api.roasos.com/v1/jobs/gen_…/result -H "Authorization: Bearer roasos_sk_live_…" ``` ## Today `POST /v1/dub/elevenlabs-dubbing` is the only path to this model. There is no deprecated alias: `POST /v1/generations` has no `dub` type, so the old path cannot reach this family at all. The source must be an MP4 your workspace owns, and at most 480 seconds. Audio-only input is refused: the provider fills its video output only from a video source, so an audio-only call returns nothing roasOS can store. ## See also https://docs.roasos.com/models/dub/elevenlabs-dubbing · https://api.roasos.com/v1/catalog/dub/elevenlabs-dubbing · fal-ai/elevenlabs/dubbing