> For a complete page index, fetch https://sync.so/docs/llms.txt

# Create Generation

POST https://api.sync.so/v2/generate
Content-Type: application/json

Create a lip sync generation with `application/json` — provide each input by `url` or by `assetId` from an uploaded asset. Use the multipart "Create Generation with Files" form only when uploading direct audio, video, or image file fields; nested fields such as input, options, segments, and dubParams must be JSON strings in multipart requests. If a `text` input requires speech synthesis and the ElevenLabs provider is temporarily unavailable, the request returns errorCode elevenlabs_service_unavailable: 504 for provider timeouts and 503 for other provider outages.

Reference: https://sync.so/docs/api-reference/api/generate-api/create

## Authentication

- `x-api-key` header (required)

## Servers

- `https://api.sync.so` (Default, default)
- `https://dev-api.sync.so` (dev)
- `http://localhost:3001` (local)

## Request

### Body (application/json)

- `model` (enum, required) — name of the model to use for generation.
  - Allowed values: `sync-3`, `lipsync-2`, `lipsync-1.9.0-beta`, `lipsync-2-pro`, `react-1`
- `input` (list of object or object or object or object, required) — Normal lipsync requests must include exactly one visual input (video or image) and one audio or text input. Dubbed lipsync requests using dubParams must include exactly one video input and no audio or text input, because Sync extracts the dubbing source audio from that video. Image inputs are only supported with the sync-3 model. When using segments, audio or text inputs can carry unique refId values.
  - Video
    - `type` ("video", required)
    - `refId` (string, optional) — Optional reference identifier for segment definitions. Use this when a segment needs to refer back to a specific visual input item.
    - `url` (string, optional) — URL of the video to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of a video asset from your media library. Either `url` or `assetId` must be provided.
    - `segments_secs` (list of list of double, optional, deprecated) — [DEPRECATED] Use the top-level [segments](/api-reference/api/generate-api/create#request.body.segments) array instead for multi-segment support.
    - `segments_frames` (list of list of integer, optional, deprecated) — [DEPRECATED] Use the top-level [segments](/api-reference/api/generate-api/create#request.body.segments) array instead for multi-segment support. frames 100 and 200 of the video
  - Image
    - `type` ("image", required)
    - `refId` (string, optional) — Optional reference identifier for segment definitions. Use this when a segment needs to refer back to a specific visual input item.
    - `url` (string, optional) — URL of the image to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of an image asset from your media library. Either `url` or `assetId` must be provided.
  - Audio
    - `type` ("audio", required)
    - `url` (string, optional) — URL of the audio to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of an audio asset from your media library. Either `url` or `assetId` must be provided.
    - `refId` (string, optional) — Reference identifier for this audio input, used to link audio inputs to specific segments when using [segments](/api-reference/api/generate-api/create#request.body.segments). Required when using segments array.
  - TTS
    - `type` ("text", required)
    - `provider` (object, required) — Integration provider configuration
      - Eleven Labs
        - `name` ("elevenlabs", required)
        - `voiceId` (string, required) — sync voice id (copied from cloned voices in the Studio) or ElevenLabs voice ID. Required.
        - `script` (string, required) — script to be used for generation
        - `stability` (double, optional, default: 0.5) — determines how stable the voice is and the randomness between each generation. lower values introduce broader emotional range for the voice. higher values can result in a monotonous voice with limited emotion.
        - `similarityBoost` (double, optional, default: 0.75) — determines how closely the ai should adhere to the original voice when attempting to replicate it.
    - `refId` (string, optional) — Reference identifier for this audio input, used to link audio inputs to specific segments when using [segments](/api-reference/api/generate-api/create#request.body.segments). Required when using segments array.
- `options` (object, optional) — additional options available for generation.
  - `sync_mode` (enum, optional, default: bounce) — Defines how to handle duration mismatches between video and audio inputs. Ignored for image inputs (images have no intrinsic duration). See the [Sync Mode](/developer-guides/sync-mode) guide for the full behavior matrix.
    - Allowed values: `bounce`, `loop`, `cut_off`, `silence`, `remap`
  - `model_mode` (enum, optional) — edit region for the model. only works with react-1. defaults to face, which affects lipsync + emotions in the face region. Available options are lips/face/head. When head is selected, model generates natural talking head movements along with emotions + lipsync.
    - Allowed values: `lips`, `face`, `head`
  - `prompt` (enum, optional) — emotion prompt for the generation. only works for react-1 model. Only single word emotions are supported at the moment.
    - Allowed values: `happy`, `sad`, `angry`, `disgusted`, `surprised`, `neutral`
  - `temperature` (double, optional, default: 0.5) — option to control how expressive lipsync can be. 0 -> least expressive, 1 -> most expressive. default:0.5
  - `active_speaker_detection` (object, optional) — Active speaker detection configuration. When enabled, automatically detects and applies lipsync only to the active speaker in videos with multiple people. Not supported for image inputs.
    - `auto_detect` (boolean, optional, default: false) — Whether to automatically detect and apply generation to the active speaker
    - `v3` (boolean, optional) — Whether to use ASD v3
    - `frame_number` (integer, optional) — Frame index that corresponds to the provided coordinates for manual speaker selection
    - `coordinates` (list of integer, optional) — Pixel coordinates [x, y] in the source video frame identified by frame_number. They are forwarded as-is to active speaker selection; they are not normalized ratios.
    - `bounding_boxes` (list of list of integer, optional) — Per-frame array of bounding boxes [x1, y1, x2, y2] for the detected face, or null if no box for that frame. Use instead of frame_number + coordinates when you already have detection data.
    - `bounding_boxes_url` (string, optional) — URL to a JSON file containing bounding boxes. Use instead of inline bounding_boxes to avoid large payloads. The JSON must have a "bounding_boxes" array with one entry per frame.
  - `occlusion_detection_enabled` (boolean, optional, default: false) — Whether to detect occlusion during generation, slows down generation speed.
- `segments` (list of object, optional) — segments definition list. When provided, allows defining one or more video segments with different audio inputs for each segment. Each segment specifies a time range and references an audio input by refId.
  - `startTime` (double, required) — Segment start time in seconds. Must be less than or equal to endTime.
  - `endTime` (double, required) — Segment end time in seconds. Must be greater than or equal to startTime.
  - `audioInput` (object, required) — Audio configuration for this segment
    - `refId` (string, required) — Reference ID of the audio/text-to-speech input to use for this segment
    - `startTime` (double, optional) — Optional start time (in seconds) to crop the referenced audio. When specified, endTime must also be provided, and startTime must be less than or equal to endTime.
    - `endTime` (double, optional) — Optional end time (in seconds) to crop the referenced audio. When specified, startTime must also be provided, and must be greater than or equal to startTime.
  - `optionsOverride` (object, optional) — Override generation options for this specific segment.
    - `sync_mode` (enum, optional, default: bounce) — Override the sync mode for this segment.
      - Allowed values: `bounce`, `loop`, `cut_off`, `silence`, `remap`
    - `temperature` (double, optional) — Override temperature (0-1) for this segment.
    - `occlusion_detection_enabled` (boolean, optional) — Override occlusion detection for this segment.
    - `active_speaker_detection` (object, optional) — Override active speaker detection for this segment. Useful when different segments have different speakers.
      - `auto_detect` (boolean, optional, default: false) — Whether to automatically detect and apply generation to the active speaker
      - `v3` (boolean, optional) — Whether to use ASD v3
      - `frame_number` (integer, optional) — Frame index that corresponds to the provided coordinates for manual speaker selection
      - `coordinates` (list of integer, optional) — Pixel coordinates [x, y] in the source video frame identified by frame_number. They are forwarded as-is to active speaker selection; they are not normalized ratios.
      - `bounding_boxes` (list of list of integer, optional) — Per-frame array of bounding boxes [x1, y1, x2, y2] for the detected face, or null if no box for that frame. Use instead of frame_number + coordinates when you already have detection data.
      - `bounding_boxes_url` (string, optional) — URL to a JSON file containing bounding boxes. Use instead of inline bounding_boxes to avoid large payloads. The JSON must have a "bounding_boxes" array with one entry per frame.
- `webhookUrl` (string, optional) — Webhook URL for generation status updates. When the generation reaches a terminal state, Sync sends a POST request with the generation payload and a Sync-Signature header. Verify the header with the organization webhook secret from GET /v2/organizations/webhook/secret. HTTPS is strongly recommended.
- `outputFileName` (string, optional) — Base filename for the generated output without extension. The .mp4 extension will be added automatically. Only alphanumeric characters, underscores, and hyphens are allowed, up to 255 characters.
- `dubParams` (object, optional) — Dubbing parameters. When present, audio is extracted from the single video input, dubbed via ElevenLabs into the target language, and then lipsync is run with the dubbed audio. Do not include audio or text inputs with dubParams; requests that send both are rejected.
  - `providerName` (enum, required) — Provider to use for dubbing.
    - Allowed values: `elevenlabs`
  - `targetLang` (enum, required) — Target language code for dubbing (e.g., "es" for Spanish, "fr" for French).
    - Allowed values: `en`, `gu`, `no`, `sl`, `pa`, `ta`, `az`, `gl`, `is`, `sw`, `my`, `fi`, `el`, `he`, `lt`, `ms`, `sv`, `fr`, `ca`, `hr`, `lv`, `ro`, `sd`, `th`, `tn`, `pl`, `ceb`, `da`, `hu`, `mr`, `tl`, `ug`, `wo`, `zu`, `zh`, `hi`, `as`, `ha`, `kk`, `ki`, `rn`, `ky`, `st`, `te`, `war`, `ak`, `be`, `cs`, `ka`, `mn`, `bo`, `ts`, `ar`, `ss`, `nl`, `tr`, `af`, `bs`, `et`, `rw`, `ne`, `ko`, `it`, `es`, `sq`, `eu`, `kn`, `sk`, `su`, `ve`, `pt`, `am`, `hy`, `doi`, `de`, `jv`, `mk`, `ja`, `vi`, `cy`, `nso`, `uk`, `bg`, `id`, `lg`, `yo`, `ml`, `fa`, `tg`, `ur`, `uz`, `ru`, `fil`
  - `sourceLang` (enum, optional) — Source language code. Defaults to "auto" for automatic detection.
    - Allowed values: `auto`, `en`, `gu`, `no`, `sl`, `pa`, `ta`, `az`, `gl`, `is`, `sw`, `my`, `fi`, `el`, `he`, `lt`, `ms`, `sv`, `fr`, `ca`, `hr`, `lv`, `ro`, `sd`, `th`, `tn`, `pl`, `ceb`, `da`, `hu`, `mr`, `tl`, `ug`, `wo`, `zu`, `zh`, `hi`, `as`, `ha`, `kk`, `ki`, `rn`, `ky`, `st`, `te`, `war`, `ak`, `be`, `cs`, `ka`, `mn`, `bo`, `ts`, `ar`, `ss`, `nl`, `tr`, `af`, `bs`, `et`, `rw`, `ne`, `ko`, `it`, `es`, `sq`, `eu`, `kn`, `sk`, `su`, `ve`, `pt`, `am`, `hy`, `doi`, `de`, `jv`, `mk`, `ja`, `vi`, `cy`, `nso`, `uk`, `bg`, `id`, `lg`, `yo`, `ml`, `fa`, `tg`, `ur`, `uz`, `ru`, `fil`
  - `numSpeakers` (integer, optional, deprecated) — [DEPRECATED] Ignored. Dubbing v2 detects speakers automatically.
- `projectId` (string, optional) — Optionally attach this generation to a project (created via POST /v2/projects) so it appears in Studio under that project. Must reference a project in your organization — otherwise the request is rejected with 422.

## Response

### 201

Job created successfully

- `createdAt` (datetime, required) — The date and time the generation was created.
- `id` (string, required) — A unique identifier for the generation.
- `input` (list of object or object or object or object, required) — An array of input objects used for generation.
  - Video
    - `type` ("video", required)
    - `refId` (string, optional) — Optional reference identifier for segment definitions. Use this when a segment needs to refer back to a specific visual input item.
    - `url` (string, optional) — URL of the video to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of a video asset from your media library. Either `url` or `assetId` must be provided.
    - `segments_secs` (list of list of double, optional, deprecated) — [DEPRECATED] Use the top-level [segments](/api-reference/api/generate-api/create#request.body.segments) array instead for multi-segment support.
    - `segments_frames` (list of list of integer, optional, deprecated) — [DEPRECATED] Use the top-level [segments](/api-reference/api/generate-api/create#request.body.segments) array instead for multi-segment support. frames 100 and 200 of the video
  - Image
    - `type` ("image", required)
    - `refId` (string, optional) — Optional reference identifier for segment definitions. Use this when a segment needs to refer back to a specific visual input item.
    - `url` (string, optional) — URL of the image to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of an image asset from your media library. Either `url` or `assetId` must be provided.
  - Audio
    - `type` ("audio", required)
    - `url` (string, optional) — URL of the audio to be used for generation. Either `url` or `assetId` must be provided.
    - `assetId` (string, optional) — ID of an audio asset from your media library. Either `url` or `assetId` must be provided.
    - `refId` (string, optional) — Reference identifier for this audio input, used to link audio inputs to specific segments when using [segments](/api-reference/api/generate-api/create#request.body.segments). Required when using segments array.
  - TTS
    - `type` ("text", required)
    - `provider` (object, required) — Integration provider configuration
      - Eleven Labs
        - `name` ("elevenlabs", required)
        - `voiceId` (string, required) — sync voice id (copied from cloned voices in the Studio) or ElevenLabs voice ID. Required.
        - `script` (string, required) — script to be used for generation
        - `stability` (double, optional, default: 0.5) — determines how stable the voice is and the randomness between each generation. lower values introduce broader emotional range for the voice. higher values can result in a monotonous voice with limited emotion.
        - `similarityBoost` (double, optional, default: 0.75) — determines how closely the ai should adhere to the original voice when attempting to replicate it.
    - `refId` (string, optional) — Reference identifier for this audio input, used to link audio inputs to specific segments when using [segments](/api-reference/api/generate-api/create#request.body.segments). Required when using segments array.
- `model` (enum, required) — The name of the model used for generation.
  - Allowed values: `sync-3`, `lipsync-2`, `lipsync-1.9.0-beta`, `lipsync-2-pro`, `react-1`
- `status` (enum, required) — The status of the generation.
  - Allowed values: `PENDING`, `PROCESSING`, `COMPLETED`, `FAILED`, `REJECTED`
- `error` (string, optional) — The error message if the generation failed.
- `errorCode` (string, optional) — Stable, machine-readable error code if the generation failed (e.g. generation_input_video_inaccessible). The full catalog of codes, messages and suggested fixes is served unauthenticated at GET /v2/errors.
- `options` (object, optional) — Options for the generation.
  - `sync_mode` (enum, optional, default: bounce) — Defines how to handle duration mismatches between video and audio inputs. Ignored for image inputs (images have no intrinsic duration). See the [Sync Mode](/developer-guides/sync-mode) guide for the full behavior matrix.
    - Allowed values: `bounce`, `loop`, `cut_off`, `silence`, `remap`
  - `model_mode` (enum, optional) — edit region for the model. only works with react-1. defaults to face, which affects lipsync + emotions in the face region. Available options are lips/face/head. When head is selected, model generates natural talking head movements along with emotions + lipsync.
    - Allowed values: `lips`, `face`, `head`
  - `prompt` (enum, optional) — emotion prompt for the generation. only works for react-1 model. Only single word emotions are supported at the moment.
    - Allowed values: `happy`, `sad`, `angry`, `disgusted`, `surprised`, `neutral`
  - `temperature` (double, optional, default: 0.5) — option to control how expressive lipsync can be. 0 -> least expressive, 1 -> most expressive. default:0.5
  - `active_speaker_detection` (object, optional) — Active speaker detection configuration. When enabled, automatically detects and applies lipsync only to the active speaker in videos with multiple people. Not supported for image inputs.
    - `auto_detect` (boolean, optional, default: false) — Whether to automatically detect and apply generation to the active speaker
    - `v3` (boolean, optional) — Whether to use ASD v3
    - `frame_number` (integer, optional) — Frame index that corresponds to the provided coordinates for manual speaker selection
    - `coordinates` (list of integer, optional) — Pixel coordinates [x, y] in the source video frame identified by frame_number. They are forwarded as-is to active speaker selection; they are not normalized ratios.
    - `bounding_boxes` (list of list of integer, optional) — Per-frame array of bounding boxes [x1, y1, x2, y2] for the detected face, or null if no box for that frame. Use instead of frame_number + coordinates when you already have detection data.
    - `bounding_boxes_url` (string, optional) — URL to a JSON file containing bounding boxes. Use instead of inline bounding_boxes to avoid large payloads. The JSON must have a "bounding_boxes" array with one entry per frame.
  - `occlusion_detection_enabled` (boolean, optional, default: false) — Whether to detect occlusion during generation, slows down generation speed.
- `outputDuration` (double, optional) — The duration of the output media.
- `outputUrl` (string, optional) — The URL of the output media.
- `outputFileName` (string, optional) — The sanitized filename applied to the output media. Characters outside letters, numbers, dashes and underscores are stripped and spaces become underscores, so this can differ from the value submitted. Null when no name was provided.
- `segments` (list of object, optional) — The segments of the generation.
  - `startTime` (double, required) — Segment start time in seconds. Must be less than or equal to endTime.
  - `endTime` (double, required) — Segment end time in seconds. Must be greater than or equal to startTime.
  - `audioInput` (object, required) — Audio configuration for this segment
    - `refId` (string, required) — Reference ID of the audio/text-to-speech input to use for this segment
    - `startTime` (double, optional) — Optional start time (in seconds) to crop the referenced audio. When specified, endTime must also be provided, and startTime must be less than or equal to endTime.
    - `endTime` (double, optional) — Optional end time (in seconds) to crop the referenced audio. When specified, startTime must also be provided, and must be greater than or equal to startTime.
  - `optionsOverride` (object, optional) — Override generation options for this specific segment.
    - `sync_mode` (enum, optional, default: bounce) — Override the sync mode for this segment.
      - Allowed values: `bounce`, `loop`, `cut_off`, `silence`, `remap`
    - `temperature` (double, optional) — Override temperature (0-1) for this segment.
    - `occlusion_detection_enabled` (boolean, optional) — Override occlusion detection for this segment.
    - `active_speaker_detection` (object, optional) — Override active speaker detection for this segment. Useful when different segments have different speakers.
      - `auto_detect` (boolean, optional, default: false) — Whether to automatically detect and apply generation to the active speaker
      - `v3` (boolean, optional) — Whether to use ASD v3
      - `frame_number` (integer, optional) — Frame index that corresponds to the provided coordinates for manual speaker selection
      - `coordinates` (list of integer, optional) — Pixel coordinates [x, y] in the source video frame identified by frame_number. They are forwarded as-is to active speaker selection; they are not normalized ratios.
      - `bounding_boxes` (list of list of integer, optional) — Per-frame array of bounding boxes [x1, y1, x2, y2] for the detected face, or null if no box for that frame. Use instead of frame_number + coordinates when you already have detection data.
      - `bounding_boxes_url` (string, optional) — URL to a JSON file containing bounding boxes. Use instead of inline bounding_boxes to avoid large payloads. The JSON must have a "bounding_boxes" array with one entry per frame.
- `segmentOutputUrl` (string, optional) — The URL of the segment output media.
- `synthesizedAudioUrl` (string, optional) — The URL of the audio synthesized from a text (TTS) input. Only present for generations created with a TTS text input; reuse it as an audio input to keep the same take across generations.
- `webhookUrl` (string, optional) — The URL to the webhook endpoint.
- `projectId` (string, optional) — The id of the project this generation is attached to, or null when it belongs to no project. Set via the projectId field on the create request.

## Examples

### sync-3

**Request**

```json
{
  "model": "sync-3",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ]
}
```

**Response**

```json
{
  "createdAt": "2026-04-07T12:00:00Z",
  "id": "id",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ],
  "model": "sync-3",
  "status": "PENDING",
  "error": "error",
  "options": {},
  "outputDuration": 10.5,
  "outputUrl": "",
  "webhookUrl": ""
}
```

**SDK Code**

```python sync-3
from sync import Sync
from sync.common import Video

client = Sync(
    api_key="YOUR_API_KEY_HERE",
)

client.generations.create(
    model="sync-3",
    input=[
        Video(
            type="video",
            url="https://assets.sync.so/docs/example-video.mp4",
        ),
        Video(
            type="audio",
            url="https://assets.sync.so/docs/example-audio.wav",
        )
    ],
)

```

```javascript sync-3
const url = 'https://api.sync.so/v2/generate';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"model":"sync-3","input":[{"type":"video","url":"https://assets.sync.so/docs/example-video.mp4"},{"type":"audio","url":"https://assets.sync.so/docs/example-audio.wav"}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go sync-3
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.sync.so/v2/generate"

	payload := strings.NewReader("{\n  \"model\": \"sync-3\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby sync-3
require 'uri'
require 'net/http'

url = URI("https://api.sync.so/v2/generate")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"sync-3\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java sync-3
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.sync.so/v2/generate")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"sync-3\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ]\n}")
  .asString();
```

```php sync-3
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.sync.so/v2/generate', [
  'body' => '{
  "model": "sync-3",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp sync-3
using RestSharp;

var client = new RestClient("https://api.sync.so/v2/generate");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"sync-3\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift sync-3
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "sync-3",
  "input": [
    [
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    ],
    [
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.sync.so/v2/generate")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### lipsync-2

**Request**

```json
{
  "model": "lipsync-2",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ],
  "options": {
    "sync_mode": "loop"
  }
}
```

**Response**

```json
{
  "createdAt": "2024-01-15T09:30:00Z",
  "id": "id",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ],
  "model": "lipsync-2",
  "status": "PENDING",
  "error": "error",
  "options": {
    "sync_mode": "loop"
  },
  "outputDuration": 10.5,
  "outputUrl": "",
  "webhookUrl": ""
}
```

**SDK Code**

```python lipsync-2
from sync import Sync
from sync.common import Video, GenerationOptions

client = Sync(
    api_key="YOUR_API_KEY_HERE",
)

client.generations.create(
    model="lipsync-2",
    input=[
        Video(
            type="video",
            url="https://assets.sync.so/docs/example-video.mp4",
        ),
        Video(
            type="audio",
            url="https://assets.sync.so/docs/example-audio.wav",
        )
    ],
    options=GenerationOptions(
        sync_mode="loop",
    ),
)

```

```javascript lipsync-2
const url = 'https://api.sync.so/v2/generate';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"model":"lipsync-2","input":[{"type":"video","url":"https://assets.sync.so/docs/example-video.mp4"},{"type":"audio","url":"https://assets.sync.so/docs/example-audio.wav"}],"options":{"sync_mode":"loop"}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go lipsync-2
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.sync.so/v2/generate"

	payload := strings.NewReader("{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ],\n  \"options\": {\n    \"sync_mode\": \"loop\"\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby lipsync-2
require 'uri'
require 'net/http'

url = URI("https://api.sync.so/v2/generate")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ],\n  \"options\": {\n    \"sync_mode\": \"loop\"\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java lipsync-2
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.sync.so/v2/generate")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ],\n  \"options\": {\n    \"sync_mode\": \"loop\"\n  }\n}")
  .asString();
```

```php lipsync-2
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.sync.so/v2/generate', [
  'body' => '{
  "model": "lipsync-2",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    },
    {
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    }
  ],
  "options": {
    "sync_mode": "loop"
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp lipsync-2
using RestSharp;

var client = new RestClient("https://api.sync.so/v2/generate");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    },\n    {\n      \"type\": \"audio\",\n      \"url\": \"https://assets.sync.so/docs/example-audio.wav\"\n    }\n  ],\n  \"options\": {\n    \"sync_mode\": \"loop\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift lipsync-2
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "lipsync-2",
  "input": [
    [
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    ],
    [
      "type": "audio",
      "url": "https://assets.sync.so/docs/example-audio.wav"
    ]
  ],
  "options": ["sync_mode": "loop"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.sync.so/v2/generate")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### dubbing

Pass dubParams to translate audio from the video and then run lipsync on the dubbed result. A single video input (with audio) is sufficient — no separate audio input is needed. Any audio inputs in the input array are ignored when dubbing is enabled.

**Request**

```json
{
  "model": "lipsync-2",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    }
  ],
  "dubParams": {
    "providerName": "elevenlabs",
    "targetLang": "es"
  }
}
```

**Response**

```json
{
  "createdAt": "2026-04-22T12:00:00Z",
  "id": "id",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    }
  ],
  "model": "lipsync-2",
  "status": "PENDING",
  "error": "",
  "options": {},
  "outputDuration": 10.5,
  "outputUrl": "",
  "webhookUrl": ""
}
```

**SDK Code**

```python dubbing
from sync import Sync
from sync.common import Video, DubDto

client = Sync(
    api_key="YOUR_API_KEY_HERE",
)

client.generations.create(
    model="lipsync-2",
    input=[
        Video(
            type="video",
            url="https://assets.sync.so/docs/example-video.mp4",
        )
    ],
    dub_params=DubDto(
        provider_name="elevenlabs",
        target_lang="es",
    ),
)

```

```javascript dubbing
const url = 'https://api.sync.so/v2/generate';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"model":"lipsync-2","input":[{"type":"video","url":"https://assets.sync.so/docs/example-video.mp4"}],"dubParams":{"providerName":"elevenlabs","targetLang":"es"}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go dubbing
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.sync.so/v2/generate"

	payload := strings.NewReader("{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    }\n  ],\n  \"dubParams\": {\n    \"providerName\": \"elevenlabs\",\n    \"targetLang\": \"es\"\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby dubbing
require 'uri'
require 'net/http'

url = URI("https://api.sync.so/v2/generate")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    }\n  ],\n  \"dubParams\": {\n    \"providerName\": \"elevenlabs\",\n    \"targetLang\": \"es\"\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java dubbing
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.sync.so/v2/generate")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    }\n  ],\n  \"dubParams\": {\n    \"providerName\": \"elevenlabs\",\n    \"targetLang\": \"es\"\n  }\n}")
  .asString();
```

```php dubbing
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.sync.so/v2/generate', [
  'body' => '{
  "model": "lipsync-2",
  "input": [
    {
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    }
  ],
  "dubParams": {
    "providerName": "elevenlabs",
    "targetLang": "es"
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp dubbing
using RestSharp;

var client = new RestClient("https://api.sync.so/v2/generate");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"lipsync-2\",\n  \"input\": [\n    {\n      \"type\": \"video\",\n      \"url\": \"https://assets.sync.so/docs/example-video.mp4\"\n    }\n  ],\n  \"dubParams\": {\n    \"providerName\": \"elevenlabs\",\n    \"targetLang\": \"es\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift dubbing
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "lipsync-2",
  "input": [
    [
      "type": "video",
      "url": "https://assets.sync.so/docs/example-video.mp4"
    ]
  ],
  "dubParams": [
    "providerName": "elevenlabs",
    "targetLang": "es"
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.sync.so/v2/generate")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```