SyncMonster API
Generate lip-sync and expression editing on videos. Find Face detects scenes
and faces in video segments and returns the same. Generate then produces
lip-sync, drama, or both on the faces you choose by face_id.
🔑 Authentication
Every request must include your API key in the request headers. Keep this key secret and never expose it in client-side code.
| Header | Value | Description |
|---|---|---|
| x-api-key | YOUR_API_KEY | Pass your secret key here |
curl -X GET \
https://api.syncmonster.ai/neuralgarage/saas/api/v1/clients/list-assets \
-H "x-api-key: YOUR_API_KEY"
🔀 How It Works
The pipeline runs in two stages. Find Face handles scene detection and face detection; Generate drives the chosen faces with lip-sync and/or drama.
/generate — that one face is used automatically. Selection matters when a scene has
multiple faces.
skip_find_face=1 directly to
POST /generate with the video attached — steps 1–3 above run inline
automatically (scene detect, face detect, auto-select) and you get back a single
request_id. Faster for the common case; use the multi-step flow when you need to
preview/choose a specific face first via /get-face.
All steps are billed per second of video.
📡 Status Codes
All API responses include a status field and a corresponding HTTP status code. Use
these to handle responses programmatically.
| Status | Name | Description |
|---|---|---|
| success | Success | The request was successful. |
| created | Created | The request has been fulfilled and a new resource has been created. |
| in_progress | In Progress | The request is being processed. |
| pending | Pending | The request is pending and awaiting processing. |
| invalid_request | Invalid Request | The request is invalid. |
| failed | Failed | The request failed to process. |
| unauthorized | Unauthorized | Authentication is required and has failed. |
| forbidden | Forbidden | You do not have permission to access this resource. |
| not_found | Not Found | The requested resource was not found. |
| internal_error | Internal Server Error | An unexpected error occurred on the server. |
🔍 Find Face
Find Face detects scenes and faces in video segments and returns the same. This runs one time per video — submit, poll for status, then fetch the faces to drive in generation.
find_face_id you poll on
/find-face/status, then read with /get-face.
| Parameter | Type | Required | Description |
|---|---|---|---|
| assets | array | Required (JSON) | Video asset with url or asset_id |
| video | file | Required (Form) | Video file upload — .mp4 or .mov |
| video_asset_id | integer | Optional | Existing video asset ID (alternative to upload) |
| options.scene_threshold | float | Optional | Scene split sensitivity |
| options.min_scene_length | integer | Optional | Minimum frames between scene cuts |
{
"assets": [
{ "type": "video", "asset_id": 123 }
],
}
video=@/path/to/video.mp4
{
"status": "success",
"message": "Find-face job created",
"data": {
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"video_asset_id": 123,
"credit_details": { "rate_per_sec": 0.5 }
}
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| find_face_id | string | Required | Find-face ID from POST /find-face |
GET /v2/find-face/status?find_face_id=ff_740006cb51da497fa1930dfe10520cc4
{
"status": "success",
"message": "Status fetched",
"data": {
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"status": "in_progress",
"status_code": 102
}
}
global_face_id to select a face in /generate.
| Parameter | Type | Required | Description |
|---|---|---|---|
| find_face_id | string | Required | Find-face ID |
GET /v2/get-face?find_face_id=ff_740006cb51da497fa1930dfe10520cc4
global_face_id and includes a base64-encoded representative image in
representative_face_base64.
| Field | Type | Description |
|---|---|---|
| global_face_id | integer | Unique identifier for the face across the find-face response |
| representative_face_base64 | string | Base64-encoded representative image for the detected face |
{
"status": "success",
"message": "Faces fetched",
"data": {
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"video_asset_id": 264,
"faces": [
{
"global_face_id": 0,
"representative_face_base64": "base64code"
},
{
"global_face_id": 1,
"representative_face_base64": "base64code"
}
]
}
}
The response can return several faces, each with global_face_id and
representative_face_base64. Pick which face(s) to drive in
/generate.
The faces array is empty. In that case, there is nothing to select and the
request has no face-based output to drive.
Only one face is returned. You can skip selection and go straight to lip-sync or drama generation — that face is used automatically.
🎬 Generate
Generate is used to produce lip-sync, drama, or both on the face you selected.
is_lipsync, is_drama, or both. Combine them to apply
emotional performance on top of lip-sync. Select a single face with
global_face_id and tune intensity via options.
skip_find_face=1 to skip
POST /find-face entirely. Send the video directly to
/generate and scene detection, face detection and
clustering all run inline, then a face is auto-selected — global_face_id defaults to
0 if omitted. One request in, one request_id out. Trade-off:
you don't get to preview detected faces via /get-face before dubbing, so
use it when you already know which face you want (or the video only has one).
| Parameter | Type | Required | Description |
|---|---|---|---|
| skip_find_face | boolean | Optional (default 0) | Set to 1 for one-shot mode — provide
video directly instead of find_face_id. See the
one-shot example below. |
| find_face_id | string | Required unless skip_find_face=1 | Completed find-face request ID (the find_face_id from
POST /find-face)
|
| video | file | Required if skip_find_face=1 (Form) | Video upload for one-shot mode — alternative to video_asset_id
or a video entry in assets (JSON) |
| video_asset_id | integer | Optional (Form, skip_find_face=1) | Existing video asset ID, reused instead of re-uploading |
| is_lipsync | boolean | Required | Enable lip-sync |
| is_drama | boolean | Required | Enable drama. May be combined with lip-sync |
| model | string | Required if is_lipsync=true | Lip-sync model — e1 Pro (recommended), e2
Adaptive, e3 Legacy |
| assets | array | Required (JSON) | Audio input with url or asset_id — plus a
video entry when skip_find_face=1 |
| audio | file | Required (Form) | Audio upload — .mp3 or .wav |
| global_face_id | integer | Required unless skip_find_face=1 | Selected face ID returned from /get-face. With
skip_find_face=1 this is optional and defaults to
0 (a face is auto-selected for you). |
| drama_params | object | Optional if is_drama=true | Same shape as drama below — {"happy":0.8,"sad":0.2,...}.
Accepted as an alternate key name (e.g. in form-data). |
| audio_asset_id | integer | Optional | Existing audio asset ID |
| options.intensity | float | Optional if is_lipsync=true | Lip-sync strength: 0.5 to 3.5. Sent in
options.
|
| drama.happy | float | Optional if is_drama=true | Happy intensity: 0 to 1 |
| drama.sad | float | Optional if is_drama=true | Sad intensity: 0 to 1 |
| drama.excited | float | Optional if is_drama=true | Excited intensity: 0 to 1 |
| drama.angry | float | Optional if is_drama=true | Angry intensity: 0 to 1 |
is_lipsync and is_drama in
any combination. At least one must be true. Use
global_face_id to select a face and send intensity in
options.
{
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"is_lipsync": true,
"is_drama": true,
"model": "e2",
"assets": [
{ "type": "audio", "asset_id": 124 }
],
"drama": {
"happy": 0.8,
"sad": 0.2,
"excited": 0.6,
"angry": 0.1
},
"options": {
"intensity": 2.0
}
}
{
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"is_lipsync": true,
"is_drama": false,
"model": "e2",
"assets": [
{ "type": "audio", "asset_id": 124 }
],
"options": { "intensity": 1.5 }
}
{
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"is_lipsync": false,
"is_drama": true,
"assets": [
{ "type": "audio", "url": "https://example.com/audio.wav" }
],
"drama": { "happy": 0.7, "excited": 0.5 }
}
find_face_id or global_face_id needed — send the video
straight in, and lip-sync/drama get applied to face global_face_id=0 (the
auto-selected face) in a single call.
{
"skip_find_face": 1,
"is_lipsync": true,
"is_drama": true,
"model": "e1",
"assets": [
{ "type": "video", "url": "https://example.com/podcastSarvam.mp4" },
{ "type": "audio", "url": "https://example.com/podcastSarvam.mp3" }
],
"drama_params": { "excited": 1 },
"options": { "intensity": 2.0 }
}
{
"status": "success",
"message": "Job Created",
"data": {
"request_id": "9fdfaf1a24d14db2b6e6821a69add99b",
"assets": [
{ "type": "video", "asset_id": 536 },
{ "type": "audio", "asset_id": 537 }
],
"auto_find_face": true
}
}
GET /get-request?request_id=... and read credit_details.credits_deducted
once status is Success. auto_find_face tells you
which billing path applied: true = one-shot (face detection + lip-sync/drama),
false = two-step (face detection already billed by the earlier
/find-face call, only lip-sync/drama billed here).
{
"status": "failed",
"message": "Invalid audio format '.txt'. Allowed: .mp4, .mov, .wav, .mp3",
"data": {
"error_code": "ERR_008",
"error_name": "INVALID_FORMAT",
"message": "Invalid file type. Supported types are: .mp4, .mov"
}
}
🎭 Lipsync & Drama Parameters
Drives mouth movement to match the supplied audio. Requires a model — pick one of
the three modes below; lipsync_intensity tunes how pronounced the sync is.
Ideal for frontal faces. Delivers natural output with high precision.
Handles a wide range of angles with balanced realism.
Generalized model designed for overall coverage across consistency and sync.
e1,
e2, e3.
| Parameter | Type | Range | Description |
|---|---|---|---|
| model | string | e1 / e2 / e3 | Lip-sync model — e1 Pro, e2 Adaptive, e3
Legacy. Required when is_lipsync=true. e1 recommended
|
| intensity | float | 0.5 – 3.5 | Sync strength: lower is subtle, higher is more pronounced |
Adds emotional performance to the driven faces. Each emotion is a float in 0 – 1
acting as its intensity. Combine emotions to shape the delivery.
Raising happy effectively lowers sad, and vice versa — they sit on the same axis.
| Parameter | Type | Range | Description |
|---|---|---|---|
| drama.happy | float | 0 – 1 | Happy intensity (inverse of sad) |
| drama.sad | float | 0 – 1 | Sad intensity (inverse of happy) |
| drama.excited | float | 0 – 1 | Excited intensity |
| drama.angry | float | 0 – 1 | Angry intensity |
After /get-face returns the detected faces, choose the face to drive using
global_face_id. Send lip-sync intensity inside options.
{
"find_face_id": "65bf2dc3926d48498ac76c7aae539647",
"global_face_id": 0,
"options": { "intensity": 2.5 }
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string | Required | The job request ID returned from POST /generate |
GET /get-status?find_face_id=a1b2c3d4e5f6g7h8
{
"status": "success",
"message": "Request status fetched",
"data": {
"request_id": "a1b2c3d4e5f6g7h8",
"status": "Success",
"status_code": "success",
"assets": { "video": 38, "audio": 45 }
}
}
{
"status": "failed",
"message": "Request ID not found"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string | Required | The completed job request ID |
GET /get-file?request_id=a1b2c3d4e5f6g7h8
Content-Type: video/mp4 Content-Disposition: attachment; filename="output.mp4" // Binary video data stream
{
"status": "success",
"data": {
"request_id": "a1b2c3d4e5f6g7h8",
"status": "in_progress",
"status_code": 102,
"message": "Job is still processing. Please try again later."
}
}
📦 Assets & Requests
Utility endpoints for listing and inspecting requests and uploaded assets.
| Parameter | Type | Default | Description |
|---|---|---|---|
| limit | integer | 10 | Records to return per page |
| offset | integer | 0 | Starting offset for pagination |
| type | string | all | Optional filter: generate, find-face, or omit to
return all requests |
GET /list-requests?limit=10&offset=0&type=generate GET /list-requests?limit=10&offset=0&type=find-face GET /list-requests?limit=10&offset=0
{
"status": "success",
"message": "Requests fetched",
"data": {
"requests": [
{
"request_id": "eca2322beafb427fb26fe39d90714ef5",
"type": "generate",
"status": "Success",
"status_code": "success",
"created_at": "2026-07-10T11:44:23",
"completed_at": "2026-07-10T11:50:26"
}
],
"total_requests": 19,
"end_of_records": false
}
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string | Required | Find-face or generate request ID |
GET /get-request?request_id=a1b2c3d4e5f6g7h8
{
"status": "success",
"message": "Request fetched",
"data": {
"request_id": "a1b2c3d4e5f6g7h8",
"type": "generate",
"status": "Success",
"status_code": "success",
"is_lipsync": true,
"is_drama": true,
"model": "e2",
"assets": { "video": 123, "audio": 124 },
"created_at": "2026-04-07T04:13:23",
"completed_at": "2026-04-07T04:14:04",
"credit_details": { "credits_deducted": 2 }
}
}
No parameters required. Returns all assets associated with your API key.
GET /list-assets
{
"status": "success",
"message": "Assets listed",
"data": [
{ "asset_id": 123, "media_type": "video" },
{ "asset_id": 124, "media_type": "audio" },
{ "asset_id": 125, "media_type": "video" }
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| asset_id | integer | Required | The asset ID to retrieve |
GET /get-asset?asset_id=123
{
"status": "success",
"message": "Asset Fetched",
"data": {
"asset_id": 123,
"media_type": "video"
}
}
{
"status": "failed",
"message": "Asset not found"
}
🛠️ Utility Endpoints
Check your credit balance and confirm that the service is healthy.
x-api-key header used by the rest of the API.
{
"status": "success",
"message": "Credits fetched",
"data": {
"credits": 1234.0
}
}
{
"status": "success",
"message": "OK",
"data": {
"status": "healthy"
}
}
⚙️ Processing Phases
/find-face and can be skipped if the video was already processed.
⚠️ Error Codes
| Code | Name | Description |
|---|---|---|
| ERR_003 | INTERNAL_SERVER_ERROR | An internal server error occurred |
| ERR_004 | NO_FACE_FOUND | No face was detected in the provided video |
| ERR_006 | INSUFFICIENT_CREDITS | Not enough credits to complete the request |
| ERR_007 | DATA_CORRUPTED | Uploaded data is corrupted or invalid |
| ERR_008 | INVALID_FORMAT | Unsupported file type. Accepted: .mp4, .mov, .mp3, .wav |
| ERR_009 | LIMIT_EXCEEDS | Video duration exceeds the limit. |