Generating Lip Sync
Learn how to generate AI lip sync videos using URLs or direct file uploads.
Chamelaion provides two endpoints for generating lip sync videos — one that accepts media URLs and another that accepts direct file uploads. Both create an asynchronous job and return a request_id for tracking.
Option 1: Generate from URLs
Section titled “Option 1: Generate from URLs”Use POST /v1/lipsync/generate when your video and audio are hosted at publicly accessible URLs. This is the most common integration pattern.
Request format
Section titled “Request format”{ "reference_id": "optional-your-id", "disable_active_speaker_detection": false, "inputs": [ { "type": "video", "url": "https://example.com/source-video.mp4" }, { "type": "audio", "url": "https://example.com/target-audio.wav" } ]}Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
inputs | array | Yes | Exactly two items — one video and one audio input (order doesn’t matter) |
inputs[].type | string | Yes | Either "video" or "audio" |
inputs[].url | string | Yes | Publicly accessible URL to the media file |
reference_id | string | No | Your own identifier for this request — useful for linking to your systems |
disable_active_speaker_detection | boolean | No | Set to true to skip speaker detection and use max-face mode (default: false) |
cURL example
Section titled “cURL example”curl -X POST https://api.chamelaion.com/api/v1/lipsync/generate \ -H "Authorization: Bearer $CHAMELAION_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reference_id": "dub-episode-42", "inputs": [ {"type": "video", "url": "https://cdn.example.com/episodes/42.mp4"}, {"type": "audio", "url": "https://cdn.example.com/dubs/42-japanese.wav"} ] }'Python example
Section titled “Python example”import requestsimport os
response = requests.post( "https://api.chamelaion.com/api/v1/lipsync/generate", headers={ "Authorization": f"Bearer {os.environ['CHAMELAION_API_KEY']}", "Content-Type": "application/json", }, json={ "reference_id": "dub-episode-42", "inputs": [ {"type": "video", "url": "https://cdn.example.com/episodes/42.mp4"}, {"type": "audio", "url": "https://cdn.example.com/dubs/42-japanese.wav"}, ], },)
result = response.json()print(f"Request ID: {result['request_id']}")TypeScript example
Section titled “TypeScript example”const response = await fetch( "https://api.chamelaion.com/api/v1/lipsync/generate", { method: "POST", headers: { Authorization: `Bearer ${process.env.CHAMELAION_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ reference_id: "dub-episode-42", inputs: [ { type: "video", url: "https://cdn.example.com/episodes/42.mp4" }, { type: "audio", url: "https://cdn.example.com/dubs/42-japanese.wav" }, ], }), });
const result = await response.json();console.log(`Request ID: ${result.request_id}`);Response
Section titled “Response”{ "status": "success", "request_id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8"}Option 2: Generate from uploaded files
Section titled “Option 2: Generate from uploaded files”Use POST /v1/lipsync/generate-with-media when you need to upload files directly rather than providing URLs. This endpoint accepts multipart/form-data.
Parameters
Section titled “Parameters”| Field | Type | Required | Description |
|---|---|---|---|
video | file | Yes | Source video file (MP4) |
audio | file | Yes | Target audio file (WAV or MP3) |
model | string | No | Model to use (currently "lipsync-2") |
reference_id | string | No | Your own identifier for this request |
disable_active_speaker_detection | boolean | No | Set to true to skip speaker detection (default: false) |
cURL example
Section titled “cURL example”curl -X POST https://api.chamelaion.com/api/v1/lipsync/generate-with-media \ -H "Authorization: Bearer $CHAMELAION_API_KEY" \ -F "video=@/path/to/source-video.mp4" \ -F "audio=@/path/to/target-audio.wav" \ -F "reference_id=upload-demo-01"Python example
Section titled “Python example”import requestsimport os
with open("source-video.mp4", "rb") as video, open("target-audio.wav", "rb") as audio: response = requests.post( "https://api.chamelaion.com/api/v1/lipsync/generate-with-media", headers={"Authorization": f"Bearer {os.environ['CHAMELAION_API_KEY']}"}, files={ "video": ("video.mp4", video, "video/mp4"), "audio": ("audio.wav", audio, "audio/wav"), }, data={ "reference_id": "upload-demo-01", }, )
result = response.json()print(f"Request ID: {result['request_id']}")TypeScript example (Node.js)
Section titled “TypeScript example (Node.js)”import { createReadStream } from "fs";
const formData = new FormData();formData.append("video", createReadStream("source-video.mp4"));formData.append("audio", createReadStream("target-audio.wav"));formData.append("reference_id", "upload-demo-01");
const response = await fetch( "https://api.chamelaion.com/api/v1/lipsync/generate-with-media", { method: "POST", headers: { Authorization: `Bearer ${process.env.CHAMELAION_API_KEY}`, }, body: formData, });
const result = await response.json();console.log(`Request ID: ${result.request_id}`);The response format is identical to the URL-based endpoint.
Active speaker detection
Section titled “Active speaker detection”By default, Chamelaion uses active speaker detection to identify which face in the video is speaking and only applies lip sync to that face. This is useful for:
- Multi-person interview or conversation videos
- Videos with background faces or audience members
- News broadcasts with anchor and on-screen graphics
To disable this and use max-face mode (syncs the largest detected face), set disable_active_speaker_detection to true:
{ "disable_active_speaker_detection": true, "inputs": [ {"type": "video", "url": "https://example.com/single-speaker.mp4"}, {"type": "audio", "url": "https://example.com/new-audio.wav"} ]}Using reference IDs
Section titled “Using reference IDs”The reference_id field lets you tag requests with your own identifiers. This is useful for:
- Linking Chamelaion requests to your internal database records
- Retrieving requests by your own ID instead of the Chamelaion UUID
- Batch tracking and reporting
{ "reference_id": "order-12345-japanese-dub", "inputs": [ {"type": "video", "url": "https://example.com/video.mp4"}, {"type": "audio", "url": "https://example.com/audio.wav"} ]}You can then retrieve the request using:
curl https://api.chamelaion.com/api/v1/lipsync/requests/order-12345-japanese-dub \ -H "Authorization: Bearer $CHAMELAION_API_KEY"Or filter your request list:
curl "https://api.chamelaion.com/api/v1/lipsync/requests?reference_id=order-12345-japanese-dub" \ -H "Authorization: Bearer $CHAMELAION_API_KEY"Which endpoint should I use?
Section titled “Which endpoint should I use?”Use URL-based generation when…
- Your media is already hosted (S3, GCS, CDN, etc.)
- You’re building a server-side pipeline
- You want to avoid upload overhead
- You’re processing many files in a batch workflow
Use file upload when…
- You’re working with local files
- Your media isn’t publicly accessible
- You’re building a desktop or CLI tool
- You need to process files before they’re stored permanently