SyncMonster Drama API
Add emotional performance — drama — to the faces in a video. There are two ways
to integrate: One-Step Drama sends a video straight in and auto-selects the face,
while Find Face + Drama detects every face first so you can pick a specific one
by global_face_id in multi-face videos.
🔑 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
Drama can be run two ways. Pick the option that fits your use case — both end with the same polling and download steps.
Send the video straight to /generate with skip_find_face=1.
Scene detection, face detection and face selection all run inline and a face is
auto-selected. Fastest path — one request in, one request_id out.
- Best when the video has a single face, or you already know which face to drive.
- No face preview before generation.
Run /find-face first to detect every face, review them via
/get-face, then pass the chosen global_face_id to
/generate.
- Gives the client full control to select a single face in multi-face videos.
- Preview each detected face before spending drama credits.
All steps are billed per second of video.
/find-face,
so /generate only bills the drama.
📡 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. |
⚡ Option 1 · One-Step Drama
Send a video straight to /generate with skip_find_face=1. Scene
detection, face detection and face selection run inline, then drama is applied to the
auto-selected face — all in a single call.
skip_find_face=1 and send the video directly. Scene
detection, face detection and clustering all run inline and a face is auto-selected —
global_face_id defaults to 0 if omitted. Trade-off: you don't
get to preview detected faces before generation, so use this when the video has one
face or you already know which face you want.
| Parameter | Type | Required | Description |
|---|---|---|---|
| skip_find_face | boolean | Required (set to 1) | Enables one-shot mode — provide video directly instead of a
find_face_id |
| is_drama | boolean | Required (true) | Enable drama generation |
| assets | array | Required (JSON) | A video entry plus an audio entry, each with a
url or asset_id |
| video | file | Required (Form) | Video upload — .mp4 or .mov. Alternative to a
video entry in assets |
| audio | file | Required (Form) | Audio upload — .mp3 or .wav |
| video_asset_id | integer | Optional | Existing video asset ID, reused instead of re-uploading |
| audio_asset_id | integer | Optional | Existing audio asset ID |
| global_face_id | integer | Optional (default 0) | A face is auto-selected for you; defaults to 0 if omitted |
| drama / drama_params | object | Optional | Emotion intensities — {"happy":0.8,"sad":0.2,...}. See
Drama Parameters. drama_params is
accepted as an alternate key (e.g. in form-data) |
{
"skip_find_face": 1,
"is_drama": true,
"assets": [
{ "type": "video", "url": "https://example.com/clip.mp4" },
{ "type": "audio", "url": "https://example.com/clip.mp3" }
],
"drama_params": { "excited": 1 }
}
skip_find_face=1
is_drama=true
video=@/path/to/clip.mp4
audio=@/path/to/clip.mp3
drama_params={"happy":0.7,"excited":0.5}
{
"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. Here auto_find_face: true confirms the one-shot
billing path (face detection + drama).
{
"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"
}
}
GET /get-status until the job
is Success, then download with
GET /get-file.
🔍 Option 2 · Find Face + Drama
Detect every face in the video first, review them, then apply drama to the single face you choose. This is the path to use when a video has multiple faces and the client needs control over which person is driven.
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 to drive with drama in
/generate — this is where the client gets control over multi-face videos.
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 drama generation — that face is used automatically.
find_face_id from Option 2 and the
global_face_id you chose in /get-face. Set
is_drama=true and shape the performance via the drama
object.
| Parameter | Type | Required | Description |
|---|---|---|---|
| find_face_id | string | Required | Completed find-face request ID (from POST /find-face) |
| global_face_id | integer | Required | Selected face ID returned from /get-face |
| is_drama | boolean | Required (true) | Enable drama generation |
| assets | array | Required (JSON) | Audio input with url or asset_id |
| audio | file | Required (Form) | Audio upload — .mp3 or .wav |
| audio_asset_id | integer | Optional | Existing audio asset ID |
| drama / drama_params | object | Optional | Emotion intensities — {"happy":0.8,"sad":0.2,...}. See
Drama Parameters |
{
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"global_face_id": 0,
"is_drama": true,
"assets": [
{ "type": "audio", "asset_id": 124 }
],
"drama": {
"happy": 0.8,
"sad": 0.2,
"excited": 0.6,
"angry": 0.1
}
}
{
"find_face_id": "ff_740006cb51da497fa1930dfe10520cc4",
"global_face_id": 1,
"is_drama": true,
"assets": [
{ "type": "audio", "url": "https://example.com/audio.wav" }
],
"drama": { "happy": 0.7, "excited": 0.5 }
}
{
"status": "success",
"message": "Job Created",
"data": {
"request_id": "9fdfaf1a24d14db2b6e6821a69add99b",
"assets": [
{ "type": "audio", "asset_id": 537 }
],
"auto_find_face": false
}
}
/find-face, this call only bills drama (1 credit/sec, charged for the
scenes that matched the selected face). auto_find_face: false confirms the
two-step billing path. Read credit_details.credits_deducted from
GET /get-request once the job is Success.
GET /get-status until the job
is Success, then download with
GET /get-file.
🎭 Drama Parameters
Drama adds emotional performance to the driven face. Each emotion is a float in
0 – 1 acting as its intensity. Combine emotions to shape the delivery. Applies to
both options above.
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 |
drama (JSON) or drama_params
(alternate key, e.g. in form-data). Omit any emotion to leave it at its default.
📥 Track & Download
Both options return a request_id. Poll it until the job succeeds, then download the
final video.
| Parameter | Type | Required | Description |
|---|---|---|---|
| request_id | string | Required | The job request ID returned from POST /generate |
GET /get-status?request_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_drama": true,
"global_face_id": 0,
"drama": { "happy": 0.8, "excited": 0.6 },
"assets": { "video": 123, "audio": 124 },
"created_at": "2026-04-07T04:13:23",
"completed_at": "2026-04-07T04:14:04",
"credit_details": { "credits_deducted": 1 }
}
}
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 (or inline in one-step mode) 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. |