Sync Lipsync V3 API, Sync Lipsync V2 Pro API: Pricing, Documentation
by Sync.so
Sync Lipsync V3 API is a powerful, automated solution designed to perfectly synchronize character and avatar lip movements with provided audio tracks. By leveraging advanced artificial intelligence, it eliminates manual frame-by-frame animation, drastically reducing production time. Developers can seamlessly integrate this tool to deliver highly realistic, localized, and expressive facial animations across gaming, film, and virtual communication platforms.

Models Version
Get $5 Free Credit on First Payment
No strings attached — add funds and get $5 bonus instantly
Sync Lipsync v3 API Documentation
POST https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync
Authentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Video + Audio to Video - Sync Lipsync v3
Request Code
POST https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync
Content-Type: application/json
Cache-Control: no-cache
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
import requests
url = "https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
payload = {
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
resp = requests.post(url, headers=headers, json=payload)
print(resp.json()) # { "request_id": "...", "status": "QUEUED", "polling_url": "..." }
const res = await fetch("https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
video_url: "https://example.com/input.mp4",
audio_url: "https://example.com/voice.mp3",
sync_mode: "cut_off"
})
});
const data = await res.json();
console.log(data); // { request_id, status: "QUEUED", polling_url }
curl -X POST "https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY" \
--data-raw '{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}'
Output
{
"request_id": "sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Webhook (Optional)
Instead of polling, you can receive a callback when the request reaches a terminal state. Pass the webhook headers on the submit request; the gateway will POST the result to your URL.
| Header | Type | Required | Description |
|---|---|---|---|
| X-Webhook-URL | string | No | HTTPS URL to receive the callback. Providing it enables webhook delivery. |
| X-Webhook-Mode | string | No | terminal (default) fires once on COMPLETED/ERROR; sync fires on each status transition. |
Example: enable webhook
curl -X POST "https://gateway.pixazo.ai/sync-lipsync-v3/v1/video-to-video/lip-sync" \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY" \
-H "X-Webhook-URL: https://your-server.com/webhooks/pixazo" \
-H "X-Webhook-Mode: terminal" \
--data-raw '{ "video_url": "https://example.com/input.mp4", "audio_url": "https://example.com/voice.mp3" }'
Callback Payload (success)
{
"request_id": "sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "sync-lipsync-v3",
"output": {
"media_url": ["https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/sync-lipsync-v3_019dxxxx.../output.mp4"],
"media_type": "video/mp4"
}
}
Failure callback shape
{
"request_id": "sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"error": "Failed to download the file. Please check if the URL is accessible."
}
- terminal mode delivers one callback on COMPLETED or ERROR; sync mode delivers on each status transition.
- Deliveries are keyed by
request_id— make your handler idempotent. - Respond with HTTP 200 within a few seconds; non-2xx responses are retried.
- The webhook URL must be HTTPS and publicly reachable.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
| video_url | Yes | string | — | — | Upload the talking-head video clip whose lips will be re-synced to your audio. |
| audio_url | Yes | string | — | — | Upload the audio track to sync the video's lips to. |
| sync_mode | No | string | cut_off | cut_off, loop, bounce, silence, remap | How to handle a duration mismatch between the audio and video. cut_off truncates the longer stream; loop repeats the shorter stream; bounce plays forward then backward; silence pads with silence; remap time-stretches the audio to match the video. |
| options | No | object | — | — | Optional container for advanced Sync.so generation settings (see the options.* rows below). If options.sync_mode is set, it overrides the top-level sync_mode. |
| options.sync_mode | No | string | — | cut_off, loop, bounce, silence, remap | How to handle a duration mismatch between the audio and video; overrides the top-level sync_mode when provided. |
| options.model_mode | No | string | — | lips, face, head, lipsync, emotion, talking_head | Edit region for the model. A Sync.so option primarily used by react-1. |
| options.prompt | No | string | — | happy, sad, angry, disgusted, surprised, neutral | Emotion prompt for generation. A Sync.so option primarily used by react-1. |
| options.temperature | No | float | — | 0 – 1 | Controls how expressive the lipsync can be; 0 is least expressive, 1 is most expressive. Sync.so handles this natively for sync-3, so this option is ignored by this model. |
| options.active_speaker_detection | No | object | — | — | Active-speaker detection settings for videos with multiple people. Supports auto_detect (boolean), v3 (boolean), frame_number (integer), coordinates ([x, y]), bounding_boxes (per-frame [x1, y1, x2, y2]), bounding_boxes_url (JSON file URL), and face_image (base64) for manual speaker selection. |
| options.occlusion_detection_enabled | No | boolean | — | true, false | Whether to detect occlusion during generation. Sync.so handles this automatically for sync-3, so this option is ignored by this model. |
Content Item Types & Limits
| Type | Max | Format / Size | Description |
|---|---|---|---|
| video | 1 | MP4, MOV | Source video. |
| audio | 1 | MP3, WAV | Voice / audio track. |
Example Request
{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
Example Response
{
"request_id": "sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Request Headers
| Header | Required | Description |
|---|---|---|
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| Content-Type | Yes | Must be application/json. |
| X-Webhook-URL | No | HTTPS callback URL (see Webhook section). |
Response Handling
Common status codes returned by the submit endpoint.
| Status Code | Meaning |
|---|---|
| 202 Accepted | Request queued. Returns request_id, status: "QUEUED", and polling_url. |
| 400 Bad Request | Invalid request body or unknown model. |
| 401 Unauthorized | Missing or invalid subscription key. |
| 402 Payment Required | Insufficient wallet balance. |
| 403 Forbidden | Subscription not permitted to access this API. |
| 429 Too Many Requests | Rate limit exceeded. |
| 500 Internal Server Error | Unexpected gateway error. |
Error Responses
Queue-system errors are returned at submit time; generation errors are surfaced via the status endpoint / webhook with status: "ERROR".
// 402 — insufficient balance
{ "error": "Insufficient balance", "message": "Wallet balance is too low for this request." }
// 400 — model not found / invalid body
{ "error": "Model not found", "message": "Model 'sync-lipsync-v3' not found or is disabled" }
// generation failure (via status / webhook)
{ "request_id": "sync-lipsync-v3_019dxxxx...", "status": "ERROR", "error": "Failed to download the input file." }
Retrieving Results
Poll the status endpoint with the request_id until status is COMPLETED (or FAILED/ERROR).
curl -X GET "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY"
Completed response
{
"request_id": "sync-lipsync-v3_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "sync-lipsync-v3",
"error": null,
"output": {
"media_url": ["https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/sync-lipsync-v3_019dxxxx.../output.mp4"],
"media_type": "video/mp4"
},
"created_at": "2026-06-30T09:20:33.812Z",
"completed_at": "2026-06-30T09:22:19.000Z"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique identifier for the request. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request (sync-lipsync-v3). |
| error | string | null | Error message when the request fails; null otherwise. |
| output.media_url | string[] | Array of URLs to the generated lip-synced MP4 video. |
| output.media_type | string | MIME type of the output (video/mp4). |
| created_at | string | ISO-8601 timestamp when the request was created. |
| completed_at | string | ISO-8601 timestamp when the request reached a terminal state. |
| polling_url | string | URL to poll for status (returned on submit). |
Status Values & Flow
| Status | Meaning |
|---|---|
| QUEUED | Request accepted and waiting to be processed. |
| PROCESSING | The lip-sync job is running. |
| COMPLETED | Done — output.media_url contains the synced video. |
| FAILED / ERROR | Generation failed — see error. |
Typical workflow
QUEUED → PROCESSING → COMPLETED (or FAILED / ERROR). Submit the request, then poll GET /v2/requests/status/{request_id} (or use a webhook) until the status is terminal, then download the video from output.media_url.
Sync Lipsync v3 API Pricing
Sync Lipsync v2 Pro API Documentation
POST https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync
Authentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Video + Audio to Video - Sync Lipsync v2 Pro
Request Code
POST https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync
Content-Type: application/json
Cache-Control: no-cache
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
import requests
url = "https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
payload = {
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
resp = requests.post(url, headers=headers, json=payload)
print(resp.json()) # { "request_id": "...", "status": "QUEUED", "polling_url": "..." }
const res = await fetch("https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
video_url: "https://example.com/input.mp4",
audio_url: "https://example.com/voice.mp3",
sync_mode: "cut_off"
})
});
const data = await res.json();
console.log(data); // { request_id, status: "QUEUED", polling_url }
curl -X POST "https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY" \
--data-raw '{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}'
Output
{
"request_id": "sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Webhook (Optional)
Instead of polling, you can receive a callback when the request reaches a terminal state. Pass the webhook headers on the submit request; the gateway will POST the result to your URL.
| Header | Type | Required | Description |
|---|---|---|---|
| X-Webhook-URL | string | No | HTTPS URL to receive the callback. Providing it enables webhook delivery. |
| X-Webhook-Mode | string | No | terminal (default) fires once on COMPLETED/ERROR; sync fires on each status transition. |
Example: enable webhook
curl -X POST "https://gateway.pixazo.ai/sync-lipsync-v2-pro/v1/video-to-video/lip-sync" \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY" \
-H "X-Webhook-URL: https://your-server.com/webhooks/pixazo" \
-H "X-Webhook-Mode: terminal" \
--data-raw '{ "video_url": "https://example.com/input.mp4", "audio_url": "https://example.com/voice.mp3" }'
Callback Payload (success)
{
"request_id": "sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "sync-lipsync-v2-pro",
"output": {
"media_url": ["https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/sync-lipsync-v2-pro_019dxxxx.../output.mp4"],
"media_type": "video/mp4"
}
}
Failure callback shape
{
"request_id": "sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"error": "Failed to download the file. Please check if the URL is accessible."
}
- terminal mode delivers one callback on COMPLETED or ERROR; sync mode delivers on each status transition.
- Deliveries are keyed by
request_id— make your handler idempotent. - Respond with HTTP 200 within a few seconds; non-2xx responses are retried.
- The webhook URL must be HTTPS and publicly reachable.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
| video_url | Yes | string | — | — | Upload the talking-head video clip whose lips will be re-synced to your audio. |
| audio_url | Yes | string | — | — | Upload the audio track to sync the video's lips to. |
| sync_mode | No | string | cut_off | cut_off, loop, bounce, silence, remap | How to handle a duration mismatch between the audio and video. cut_off truncates the longer stream; loop repeats the shorter stream; bounce plays forward then backward; silence pads with silence; remap time-stretches the audio to match the video. |
Content Item Types & Limits
| Type | Max | Format / Size | Description |
|---|---|---|---|
| video | 1 | MP4, MOV | Source video. |
| audio | 1 | MP3, WAV | Voice / audio track. |
Example Request
{
"video_url": "https://example.com/input.mp4",
"audio_url": "https://example.com/voice.mp3",
"sync_mode": "cut_off"
}
Example Response
{
"request_id": "sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Request Headers
| Header | Required | Description |
|---|---|---|
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| Content-Type | Yes | Must be application/json. |
| X-Webhook-URL | No | HTTPS callback URL (see Webhook section). |
Response Handling
Common status codes returned by the submit endpoint.
| Status Code | Meaning |
|---|---|
| 202 Accepted | Request queued. Returns request_id, status: "QUEUED", and polling_url. |
| 400 Bad Request | Invalid request body or unknown model. |
| 401 Unauthorized | Missing or invalid subscription key. |
| 402 Payment Required | Insufficient wallet balance. |
| 403 Forbidden | Subscription not permitted to access this API. |
| 429 Too Many Requests | Rate limit exceeded. |
| 500 Internal Server Error | Unexpected gateway error. |
Error Responses
Queue-system errors are returned at submit time; generation errors are surfaced via the status endpoint / webhook with status: "ERROR".
// 402 — insufficient balance
{ "error": "Insufficient balance", "message": "Wallet balance is too low for this request." }
// 400 — model not found / invalid body
{ "error": "Model not found", "message": "Model 'sync-lipsync-v2-pro' not found or is disabled" }
// generation failure (via status / webhook)
{ "request_id": "sync-lipsync-v2-pro_019dxxxx...", "status": "ERROR", "error": "Failed to download the input file." }
Retrieving Results
Poll the status endpoint with the request_id until status is COMPLETED (or FAILED/ERROR).
curl -X GET "https://gateway.pixazo.ai/v2/requests/status/sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-H "Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY"
Completed response
{
"request_id": "sync-lipsync-v2-pro_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "sync-lipsync-v2-pro",
"error": null,
"output": {
"media_url": ["https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/sync-lipsync-v2-pro_019dxxxx.../output.mp4"],
"media_type": "video/mp4"
},
"created_at": "2026-06-30T09:20:33.812Z",
"completed_at": "2026-06-30T09:22:19.000Z"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique identifier for the request. |
| status | string | QUEUED, PROCESSING, COMPLETED, FAILED, or ERROR. |
| model_id | string | The model that handled the request (sync-lipsync-v2-pro). |
| error | string | null | Error message when the request fails; null otherwise. |
| output.media_url | string[] | Array of URLs to the generated lip-synced MP4 video. |
| output.media_type | string | MIME type of the output (video/mp4). |
| created_at | string | ISO-8601 timestamp when the request was created. |
| completed_at | string | ISO-8601 timestamp when the request reached a terminal state. |
| polling_url | string | URL to poll for status (returned on submit). |
Status Values & Flow
| Status | Meaning |
|---|---|
| QUEUED | Request accepted and waiting to be processed. |
| PROCESSING | The lip-sync job is running. |
| COMPLETED | Done — output.media_url contains the synced video. |
| FAILED / ERROR | Generation failed — see error. |
Typical workflow
QUEUED → PROCESSING → COMPLETED (or FAILED / ERROR). Submit the request, then poll GET /v2/requests/status/{request_id} (or use a webhook) until the status is terminal, then download the video from output.media_url.