--- title: Generating Lip Sync | Chamelaion description: 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 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 ``` { "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 | 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 Terminal window ``` 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 ``` import requests import 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 ``` 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 ``` { "status": "success", "request_id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8" } ``` ## 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 | 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 Terminal window ``` 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 ``` import requests import 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) ``` 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 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"} ] } ``` Disabling active speaker detection can speed up processing for single-speaker videos where face detection is straightforward. ## 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: Terminal window ``` curl https://api.chamelaion.com/api/v1/lipsync/requests/order-12345-japanese-dub \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` Or filter your request list: Terminal window ``` 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? 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