Skip to content
DashboardGet API Key
Getting Started

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.

  • 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

Log in to your Chamelaion Dashboard and create a new API key. Copy it somewhere safe — you’ll need it for all API requests.

Send a POST request to /v1/lipsync/generate with your video and audio URLs:

Terminal window
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"
}
]
}'
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']}")
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"
}

Lip sync generation is asynchronous. Use the request_id from Step 2 to check on your job:

Terminal window
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"
}

Once the status is completed, the output_url field contains a link to your lip-synced video. Download it or stream it directly.

Terminal window
curl -o result.mp4 "https://storage.chamelaion.com/output/6f82a2d8.mp4"

Here’s a full end-to-end script that submits a job and waits for the result:

import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.chamelaion.com/api"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1. Submit the lip sync job
response = 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 complete
while 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)