Saltar a la navegación

Dubbing

Dubbing is supported natively on POST /v2/generate. Pass the dubParams object alongside your normal generation request and Sync Labs will extract audio from the video input, dub it into the target language, and run lipsync on the dubbed result — all as one job.

A video with audio is sufficient for dubbing to work — video input alone (with an embedded audio track) is acceptable. You do not need to supply a separate audio input; any audio inputs in the input array are ignored when dubParams is present. You must pass the dub parameters (dubParams) to enable dubbing.

When to use dubbing

  • Already have translated or recorded audio? Use a normal lip sync generation with your video and an audio input. Omit dubParams so your supplied audio is used without translating it again. In Studio, choose the lip-sync workflow instead of Translate & Dub.
  • Native dubParams flow (this page): single API call, recommended for standard translation-plus-lipsync workflows.
  • Manual orchestration: when you need custom control over transcription, TTS voice cloning, or intermediate steps, see the Translation/Dubbing tutorial which wires ElevenLabs, OpenAI, and Sync Labs together manually.

Workflow

1

Prepare a video with audio

Ensure your source file is a video whose audio track you want translated. No separate audio input is required.

2

Pick a target language

Choose one of the supported targetLang codes (see the DubLanguage enum in the API Reference for the full list).

3

Send the generation request

Include dubParams in the request body. providerName and targetLang are required; sourceLang defaults to auto.

4

Poll for completion

Poll GET /v2/generate/{id} until status is COMPLETED; the outputUrl will contain the dubbed and lipsynced video.

DubDto fields

See the full API reference for dubParams.

  • providerName (DubProviderName, required): dubbing provider to use. Currently elevenlabs is the only supported value.
  • targetLang (DubLanguage, required): target language code for dubbing, e.g. es, fr, ja. Regional variants include es-MX, es-ES, and pt-BR.
  • sourceLang (DubSourceLanguage, optional, default auto): source language code, or auto to let the engine detect it.
  • cloningStrength (optional integer, 1–10): higher values preserve more of the source voice. Omit it to use the provider default.
  • startTime and endTime (optional numbers): the range to dub, in seconds. They default to the start and end of the source video.
  • numSpeakers (integer, optional): deprecated and ignored. Speakers are detected automatically. Accepted for backward compatibility only.

If you need a target language that is not listed in DubLanguage, generate or record the translated audio yourself and submit it as a normal audio input instead of using dubParams. Lipsync models can match clear audio in any language.

Dub part of a video

Set dubParams.startTime and dubParams.endTime to select a range without uploading a cut version. The output contains only that range. Billing and duration limits use the selected duration.

"dubParams": {
"providerName": "elevenlabs",
"targetLang": "es",
"startTime": 10,
"endTime": 30
}

The start must precede the end, and both must fall within the video. Invalid ranges return 422 generation_input_trim_invalid, with the field to correct.

Range dubbing is unavailable with zero data retention, a custom output bucket, a retention override, or options.output_bucket_name. Use the full video with those settings.

Reuse translated audio

After dubbing finishes, the generation response and webhook include dubAudioUrl and dubAudioAssetId. Reuse the asset as an audio input to avoid translating the same track again.

These fields are null until dubbing finishes and are omitted for generations without dubParams. dubAudioAssetId also stays null under the retention and custom-bucket settings described above.

Request examples

import { SyncClient } from "@sync.so/sdk";
const sync = new SyncClient();
const response = await sync.generations.create({
model: "lipsync-2",
input: [
{ type: "video", url: "https://assets.sync.so/docs/example-video.mp4" }
],
dubParams: {
providerName: "elevenlabs",
targetLang: "es"
}
});
from sync import Sync
client = Sync()
response = client.generations.create(
model="lipsync-2",
input=[
{"type": "video", "url": "https://assets.sync.so/docs/example-video.mp4"}
],
dub_params={
"provider_name": "elevenlabs",
"target_lang": "es"
},
)
curl -X POST https://api.sync.so/v2/generate \
-H "x-api-key: $SYNC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "lipsync-2",
"input": [
{ "type": "video", "url": "https://assets.sync.so/docs/example-video.mp4" }
],
"dubParams": {
"providerName": "elevenlabs",
"targetLang": "es"
}
}'

Behavior notes

  • When dubParams is provided, audio is extracted from the video input, dubbed via ElevenLabs into the target language, and lipsync is run against the dubbed audio.
  • Pass only the video input with dubParams. Requests that also include audio or text inputs are rejected.
  • A probed audio duration is required on the source video; dubbing requests without a decodable audio track are rejected.
  • Dubbing audio and lip sync are charged separately. Dubbing audio is billed per second, rounded up per job. See dubbing pricing for dollar rates and rollout timing, or credit pricing for credit consumption.

Free accounts share 10 monthly audio generations between text-to-speech and dubbing. Up to 3 of those 10 can be dubbing, with a 20-second source limit per free dub. If you do not use dubbing, all 10 can be used for text-to-speech. Lip sync uses its own free allowance. See Free Trial.

See also