> For the documentation index, fetch https://sync.so/docs/llms.txt. Append .md to a page URL for Markdown. Documentation-search MCP: https://sync.so/docs/_mcp/server. # 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. For reusable or large local files, upload them first with POST /v2/assets/upload and pass the returned `assetId`; see [Asset Uploads](/developer-guides/asset-uploads). Use the multipart "Create Generation with Files" form only when uploading direct audio, video, or image file fields; it has a 5 GiB per-file application parser limit, subject to your plan and any lower proxy limits. Nested fields such as input, options, segments, dubParams, and dialogueEdit 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 for unkeyed requests. Keyed uncertain outcomes return 503 IDEMPOTENCY_OUTCOME_UNKNOWN instead. An API-key request that passes dialogueEdit is refused with errorCode dialogue_edit_retime_required (422) when the organization's rollout lacks segment lipsync and section expansion. A dialogueEdit that removes more speech than the surrounding footage can absorb returns errorCode dialogue_edit_removal_too_large (422). When the failing section can be identified, `dialogueEditSection` on the error names it; change it and create a new preview before submitting again. Retrying the same preview fails again. Send the optional Idempotency-Key header on the first request and reuse it with the same payload on retries. An accepted replay returns 200 with the original generation's current state and Idempotency-Replayed: true. See [Idempotent Requests](/api-reference/guides/idempotency) for key validation, conflicts, retention, and uncertain-outcome recovery. Reference: https://sync.so/docs/api-reference/api/generate-api/create ## Authentication - `x-api-key` header (required) — API Key authentication via header ## Servers - `https://api.sync.so` (Default, default) - `https://dev-api.sync.so` (dev) - `http://localhost:3001` (local) ## Request ### Headers - `Idempotency-Key` (string, optional) — Case-sensitive organization-scoped key, 1–128 characters matching [A-Za-z0-9._~-]+. Send exactly one header. Reuse the same key and payload for retries of one action. Retained seven days from acceptance, longer while active or unresolved. Not a JSON field. ### Body (application/json) This endpoint expects a CreateGenerationDto. - `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 Input, 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. - `options` (GenerationOptions, optional) — additional options available for generation. - `segments` (list of GenerationSegment, 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. - `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` (DubDto, 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. - `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. - `dialogueEdit` (DialogueEditReference, optional) — Use the id of a completed dialogue edit from POST /v2/dialogue-edits to supply the audio and edited regions. Requires a preview that ran segment lipsync and section expansion (see the job's segmentLipsyncEnabled and sectionExpansionEnabled). Send exactly one video input, the same video the dialogue edit was made from, and no audio input, segments or dubParams. Billing, status, wait and webhooks work as for any generation. ## Response ### 201 First acceptance returns 201. An equivalent keyed replay returns 200 with this same response shape and Idempotency-Replayed: true. The original generation may still be processing or may have failed. - `createdAt` (datetime, required) — The date and time the generation was created. - `id` (string, required) — A unique identifier for the generation. - `input` (list of Input, required) — An array of input objects used for generation. - `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` (GenerationOptions, optional) — Options for the generation. - `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 GenerationSegment, optional) — The segments of the generation. - `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. - `generationEstimate` (GenerationEstimate, optional) — A completion-time estimate captured once when the generation is accepted. Populated only for generations created in sync's own apps, such as Sync Studio; the field is absent for generations created through the API today. ## Errors ### 400 Bad Request Error Bad Request - Invalid input or unsupported model - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 401 Unauthorized Error Unauthorized - Invalid or missing authentication - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 422 Unprocessable Entity Error Unprocessable Entity - The requested generation is not downloadable (generation_not_downloadable), or submit-time validation failed (e.g. inaccessible media, invalid segments, a projectId/voiceId/assetId that does not resolve in your organization, or a file exceeding the plan size limit). The body carries a stable errorCode and, where applicable, the failing field. - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 409 Conflict Error Conflict - The resource is in a state that does not allow the requested action (e.g. deleting a generation that is still processing). For creation, generation_conflict indicates a duplicate internal backend submission. Keyed creates return IDEMPOTENCY_KEY_CONFLICT for a changed payload or IDEMPOTENCY_IN_PROGRESS while the original request prepares (Retry-After: 2). Retry only with the same key and original inputs after an ambiguous network failure. See [Idempotent Requests](/api-reference/guides/idempotency). - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 410 Generation Deleted Error The original keyed generation was deleted. The key remains bound until expiry; an equivalent retry does not create a replacement generation. - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 429 Generation Too Many Requests Error Too Many Requests - generation concurrency limit reached. Check the concurrency_limit_reached errorCode and the retry/concurrency fields. - `statusCode` (double, required) — The HTTP status code (429). - `message` (GenerationErrorMessage, required) — A human-readable description of the error. - `errorCode` (string, optional) — Machine-readable error code (`concurrency_limit_reached`). - `activeGenerations` (double, optional) — The number of generations you currently have in progress. - `concurrencyLimit` (double, optional) — The maximum number of concurrent generations allowed on your plan. - `retryAfterSeconds` (double, optional) — Suggested number of seconds to wait before retrying. Mirrors the `Retry-After` header. ### 503 Service Unavailable Error Service Unavailable - A sync. labs service or provider dependency is temporarily unavailable. The body carries a stable errorCode such as elevenlabs_service_unavailable or controller_dependency_error. Keyed generation creates may return IDEMPOTENCY_OUTCOME_UNKNOWN when acceptance needs reconciliation, or IDEMPOTENCY_UNAVAILABLE when new keyed admission is disabled. Preserve the same key and payload; do not bypass protection. generation_admission_paused means new generation requests are paused for maintenance; generation_admission_unavailable means the API can't confirm it is accepting them. Retry after Retry-After. - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 504 Gateway Timeout Error Gateway Timeout - A sync. labs service or provider dependency timed out. The body carries a stable errorCode such as elevenlabs_service_unavailable or controller_timeout. - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ### 500 Internal Server Error Internal Server Error - An unexpected failure on our side. The body carries errorCode internal_error and a requestId; include the requestId when contacting support. - `message` (GenerationErrorMessage, required) — A message describing the error. - `statusCode` (double, required) — The type of error that occurred. - `errorCode` (string, optional) — Stable, machine-readable error code (e.g. project_not_found, voice_not_found, concurrency_limit_reached). Branch your error handling on this, not on the message text. The full catalog of codes with messages and suggested fixes is served unauthenticated at GET /v2/errors. - `suggestion` (string, optional) — A suggested fix an agent can act on. - `field` (string, optional) — The request field the error refers to, when the failure is tied to a specific field (e.g. projectId, voiceId, input[].assetId). - `docsUrl` (string, optional) — Link to the documentation page for the failing operation. - `requestId` (string, optional) — Present on unexpected 500 responses. Include it when contacting support so the failing request can be located directly. - `generationId` (string, optional) — Original generation ID when available for an uncertain keyed submission. Poll this ID; do not create another action to bypass IDEMPOTENCY_OUTCOME_UNKNOWN. - `dialogueEditSection` (DialogueEditRetimeFailureSection, optional) — For dialogue_edit_removal_too_large: the section to change, when it can be identified. Create a new dialogue edit preview before submitting again. ## Types ### Input An input item for a generation. ### GenerationOptions - `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, default: face) — 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` (string, optional, default: neutral) — Prompt for the generation. React-1 accepts emotion prompts; the appearance model accepts a free-form appearance edit instruction. - `prompt_image_uris` (list of string, optional) — Reference image URLs for appearance editing generations. - `i2v_prompt` (string, optional) — Prompt for image-to-video generation. - `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` (ActiveSpeaker, 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. - `face_boxes_url` (string, optional) — URL for precomputed face bounding boxes. - `refinement_enabled` (boolean, optional) — Whether to enable the refinement pass for the generation. - `blending_mode` (enum, optional) — Controls how generated frames blend into the source media. - Allowed values: `default`, `advanced`, `disabled` - `occlusion_detection_enabled` (boolean, optional, default: false) — Whether to detect occlusion during generation, slows down generation speed. - `output_format` (enum, optional, default: mp4, deprecated) — Deprecated output container setting; defaults to mp4. - Allowed values: `mp4`, `mov` - `fps` (double, optional, deprecated) — Deprecated output frame-rate setting. - `output_resolution` (list of double, optional, deprecated) — Deprecated output resolution setting, as exactly [width, height]. Each value must be finite and between 180 and 4096 inclusive. Invalid values are discarded and the option is treated as omitted. ### GenerationSegment Defines a video segment with its corresponding audio input. Used for multi-segment lipsync generations where different audio tracks can be applied to different video segments. - `audioInput` (SegmentAudioInput, required) — Audio configuration for this segment - `startTime` (double, optional) — Segment start time in seconds. Must be less than or equal to endTime. - `endTime` (double, optional) — Segment end time in seconds. Must be greater than or equal to startTime. - `startFrame` (double, optional) — Segment start frame. Use with endFrame instead of time bounds. - `endFrame` (double, optional) — Segment end frame. Use with startFrame instead of time bounds. - `optionsOverride` (SegmentOptionsOverride, optional) — Override generation options for this specific segment. ### DubDto Dubbing parameters attached to a generate request. - `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, default: auto) — 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. ### DialogueEditReference Reference to a completed dialogue edit to generate a video from. - `id` (string, required) — Id of a completed dialogue edit from POST /v2/dialogue-edits. ### GenerationEstimate A completion-time estimate produced when a generation is accepted. - `estimatedDurationSeconds` (double, required) — Estimated generation duration in seconds. - `estimatedFinishAt` (datetime, required) — Estimated completion timestamp a client shows for the remaining wait. - `delayedAt` (datetime, required) — Timestamp after which the generation is considered delayed relative to the estimate. - `supportAt` (datetime, required) — Timestamp after which contacting support is suggested. - `estimatedAt` (datetime, required) — When the estimate was computed. - `serverTime` (datetime, required) — Current server time, stamped when the response was built. - `calibrationAsOf` (datetime, required) — When the calibration snapshot behind the estimate was last refreshed. - `estimatorVersion` (string, required) — Version of the estimator that produced the estimate. - `confidence` (enum, required) — The estimate's confidence level. - Allowed values: `measured`, `approximate`, `fallback` - `source` (enum, required) — The data source the estimate was derived from. - Allowed values: `cohort`, `duration_neighbor`, `resolution_neighbor`, `model_pool`, `global_pool`, `fallback` - `sampleCount` (integer, required) — Number of historical samples that informed the estimate. - `scope` (enum, required) — Whether the generation is a Studio or non-Studio generation. - Allowed values: `studio`, `non_studio` - `durationBand` (string, required) — Duration bucket used to match the estimate against similar past generations. - `resolutionBand` (string, required) — Resolution bucket used to match the estimate against similar past generations. - `resolutionSource` (enum, required) — Whether the resolution came from the requested output, the input asset, or is unknown. - Allowed values: `input`, `requested_output`, `unknown` ### GenerationErrorMessage A message describing the error. ### DialogueEditRetimeFailureSection The dialogue-edit section that removes too much speech to stay in sync. - `slotIndex` (integer, required) — Zero-based index of the section in the preview's `resultSlots`. - `sourceStartMs` (integer, optional) — Start of the section in the source video, in absolute milliseconds. - `sourceDurationMs` (integer, optional) — Length of the section in the source video, in milliseconds. ### Video Video input for generation. Provide either `url` or `assetId` (one is required). - `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 Image input for sync-3 model. Use instead of video when generating from a static image. Provide either `url` or `assetId` (one is required). - `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 Recorded/Captured audio input - `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 Text to speech input - `type` ("text", required) - `provider` (TTSProviderConfig, required) — Integration provider configuration - `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. ### ActiveSpeaker Active speaker detection configuration - `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. - `face_image` (string, optional) — Base64-encoded reference face image (128x128 WebP) for selected-speaker detection. ### SegmentAudioInput Audio input configuration for a specific segment. References an audio input by refId and optionally crops the audio to a specific time range. - `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. ### SegmentOptionsOverride Override generation options for a specific segment. Any options set here will override the top-level generation options for this segment only. - `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` (ActiveSpeaker, optional) — Override active speaker detection for this segment. Useful when different segments have different speakers. ### TTSProviderConfig ### ElevenLabs - `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. ## 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 import requests url = "https://api.sync.so/v2/generate" payload = { "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 = { "x-api-key": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript sync-3 const url = 'https://api.sync.so/v2/generate'; const options = { method: 'POST', headers: {'x-api-key': '', '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", "") 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"] = '' 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 response = Unirest.post("https://api.sync.so/v2/generate") .header("x-api-key", "") .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 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' => '', ], ]); 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", ""); 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": "", "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 import requests url = "https://api.sync.so/v2/generate" payload = { "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 = { "x-api-key": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript lipsync-2 const url = 'https://api.sync.so/v2/generate'; const options = { method: 'POST', headers: {'x-api-key': '', '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", "") 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"] = '' 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 response = Unirest.post("https://api.sync.so/v2/generate") .header("x-api-key", "") .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 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' => '', ], ]); 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", ""); 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": "", "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 import requests url = "https://api.sync.so/v2/generate" payload = { "model": "lipsync-2", "input": [ { "type": "video", "url": "https://assets.sync.so/docs/example-video.mp4" } ], "dubParams": { "providerName": "elevenlabs", "targetLang": "es" } } headers = { "x-api-key": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript dubbing const url = 'https://api.sync.so/v2/generate'; const options = { method: 'POST', headers: {'x-api-key': '', '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", "") 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"] = '' 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 response = Unirest.post("https://api.sync.so/v2/generate") .header("x-api-key", "") .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 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' => '', ], ]); 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", ""); 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": "", "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() ```