Quickstart
Go from zero to your first AI lip sync generation in under five minutes.
This guide walks you through generating your first AI lip-synced video with the Chamelaion API. You’ll need an API key and a video + audio pair to get started.
Prerequisites
Section titled “Prerequisites”- A Chamelaion account with an API key (get one from the Dashboard)
- A source video URL (MP4) containing a speaking person
- A target audio URL (WAV or MP3) to sync the lips to
Step 1: Get your API key
Section titled “Step 1: Get your API key”Log in to your Chamelaion Dashboard and create a new API key. Copy it somewhere safe — you’ll need it for all API requests.
Step 2: Start a lip sync generation
Section titled “Step 2: Start a lip sync generation”Send a POST request to /v1/lipsync/generate with your video and audio URLs:
Using cURL
Section titled “Using cURL”curl -X POST https://api.chamelaion.com/api/v1/lipsync/generate \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reference_id": "my-first-lipsync", "inputs": [ { "type": "video", "url": "https://example.com/source-video.mp4" }, { "type": "audio", "url": "https://example.com/target-audio.wav" } ] }'Using Python
Section titled “Using Python”import requests
API_KEY = "YOUR_API_KEY"BASE_URL = "https://api.chamelaion.com/api"
response = requests.post( f"{BASE_URL}/v1/lipsync/generate", headers={ "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json", }, json={ "reference_id": "my-first-lipsync", "inputs": [ {"type": "video", "url": "https://example.com/source-video.mp4"}, {"type": "audio", "url": "https://example.com/target-audio.wav"}, ], },)
data = response.json()print(f"Request ID: {data['request_id']}")print(f"Status: {data['status']}")Using TypeScript
Section titled “Using TypeScript”const API_KEY = "YOUR_API_KEY";const BASE_URL = "https://api.chamelaion.com/api";
const response = await fetch(`${BASE_URL}/v1/lipsync/generate`, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ reference_id: "my-first-lipsync", inputs: [ { type: "video", url: "https://example.com/source-video.mp4" }, { type: "audio", url: "https://example.com/target-audio.wav" }, ], }),});
const data = await response.json();console.log(`Request ID: ${data.request_id}`);console.log(`Status: ${data.status}`);You’ll get back a response like:
{ "status": "success", "request_id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8"}Step 3: Poll for the result
Section titled “Step 3: Poll for the result”Lip sync generation is asynchronous. Use the request_id from Step 2 to check on your job:
curl https://api.chamelaion.com/api/v1/lipsync/requests/6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8 \ -H "Authorization: Bearer YOUR_API_KEY"The response includes the current status and, when complete, the output URL:
{ "id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8", "reference_id": "my-first-lipsync", "status": "completed", "created_at": "2026-04-07T10:00:00Z", "started_at": "2026-04-07T10:00:05Z", "finished_at": "2026-04-07T10:01:30Z", "output_url": "https://storage.chamelaion.com/output/6f82a2d8.mp4"}Step 4: Download your result
Section titled “Step 4: Download your result”Once the status is completed, the output_url field contains a link to your lip-synced video. Download it or stream it directly.
curl -o result.mp4 "https://storage.chamelaion.com/output/6f82a2d8.mp4"Complete Python example
Section titled “Complete Python example”Here’s a full end-to-end script that submits a job and waits for the result:
import requestsimport time
API_KEY = "YOUR_API_KEY"BASE_URL = "https://api.chamelaion.com/api"HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1. Submit the lip sync jobresponse = requests.post( f"{BASE_URL}/v1/lipsync/generate", headers={**HEADERS, "Content-Type": "application/json"}, json={ "reference_id": "quickstart-demo", "inputs": [ {"type": "video", "url": "https://example.com/video.mp4"}, {"type": "audio", "url": "https://example.com/audio.wav"}, ], },)response.raise_for_status()request_id = response.json()["request_id"]print(f"Submitted job: {request_id}")
# 2. Poll until completewhile True: status_response = requests.get( f"{BASE_URL}/v1/lipsync/requests/{request_id}", headers=HEADERS, ) status_response.raise_for_status() result = status_response.json()
print(f"Status: {result['status']}")
if result["status"] == "completed": print(f"Output URL: {result['output_url']}") break elif result["status"] == "failed": print(f"Error: {result.get('error_message', 'Unknown error')}") break
time.sleep(5)Next steps
Section titled “Next steps”- Learn about Authentication options
- Explore Lip Sync Generation in detail, including file uploads
- Understand Request Polling patterns
- Handle Errors gracefully