Polling & Request Status
How to check the status of lip sync jobs and list your generation history.
Chamelaion processes lip sync jobs asynchronously. After submitting a generation request, you’ll receive a request_id that you use to poll for the result. This guide covers how to check individual request status and list your generation history.
Request lifecycle
Section titled “Request lifecycle”Every lip sync request goes through these stages:
| Status | Description |
|---|---|
queued | Request received and waiting to be processed |
processing | Lip sync generation is in progress |
completed | Generation finished — output_url is available |
failed | Generation failed — check error_message for details |
Get a single request
Section titled “Get a single request”Use GET /v1/lipsync/requests/{id} to check the status of a specific request. You can pass either the Chamelaion UUID or your own reference_id.
By request ID
Section titled “By request ID”curl https://api.chamelaion.com/api/v1/lipsync/requests/6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8 \ -H "Authorization: Bearer $CHAMELAION_API_KEY"By reference ID
Section titled “By reference ID”curl https://api.chamelaion.com/api/v1/lipsync/requests/my-custom-reference \ -H "Authorization: Bearer $CHAMELAION_API_KEY"Response (completed)
Section titled “Response (completed)”{ "id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8", "reference_id": "my-custom-reference", "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"}Response (failed)
Section titled “Response (failed)”{ "id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8", "reference_id": "my-custom-reference", "status": "failed", "created_at": "2026-04-07T10:00:00Z", "started_at": "2026-04-07T10:00:05Z", "finished_at": "2026-04-07T10:00:12Z", "error_message": "video URL is not accessible"}Polling pattern
Section titled “Polling pattern”Here’s the recommended polling pattern with exponential backoff:
Python
Section titled “Python”import requestsimport timeimport os
API_KEY = os.environ["CHAMELAION_API_KEY"]BASE_URL = "https://api.chamelaion.com/api"HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def wait_for_completion(request_id: str, timeout: int = 600) -> dict: """Poll a lip sync request until it completes or fails.""" start = time.time() delay = 2
while time.time() - start < timeout: response = requests.get( f"{BASE_URL}/v1/lipsync/requests/{request_id}", headers=HEADERS, ) response.raise_for_status() result = response.json()
if result["status"] == "completed": return result elif result["status"] == "failed": raise Exception(f"Generation failed: {result.get('error_message')}")
time.sleep(delay) delay = min(delay * 1.5, 15) # cap at 15 seconds
raise TimeoutError(f"Request {request_id} did not complete within {timeout}s")TypeScript
Section titled “TypeScript”async function waitForCompletion( requestId: string, timeoutMs = 600_000): Promise<Record<string, unknown>> { const start = Date.now(); let delay = 2000;
while (Date.now() - start < timeoutMs) { const response = await fetch( `https://api.chamelaion.com/api/v1/lipsync/requests/${requestId}`, { headers: { Authorization: `Bearer ${process.env.CHAMELAION_API_KEY}` } } );
const result = await response.json();
if (result.status === "completed") return result; if (result.status === "failed") { throw new Error(`Generation failed: ${result.error_message}`); }
await new Promise((r) => setTimeout(r, delay)); delay = Math.min(delay * 1.5, 15_000); }
throw new Error(`Request ${requestId} timed out`);}List all requests
Section titled “List all requests”Use GET /v1/lipsync/requests to retrieve a paginated list of your lip sync requests.
Basic listing
Section titled “Basic listing”curl "https://api.chamelaion.com/api/v1/lipsync/requests" \ -H "Authorization: Bearer $CHAMELAION_API_KEY"With pagination
Section titled “With pagination”curl "https://api.chamelaion.com/api/v1/lipsync/requests?limit=10&offset=20" \ -H "Authorization: Bearer $CHAMELAION_API_KEY"Filter by reference ID
Section titled “Filter by reference ID”curl "https://api.chamelaion.com/api/v1/lipsync/requests?reference_id=batch-2026-04" \ -H "Authorization: Bearer $CHAMELAION_API_KEY"Query parameters
Section titled “Query parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Number of results per page (minimum 1) |
offset | integer | 0 | Number of results to skip |
reference_id | string | — | Filter by exact reference_id |
Response
Section titled “Response”{ "data": [ { "id": "6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8", "reference_id": "batch-2026-04", "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" }, { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "reference_id": "batch-2026-04", "status": "queued", "created_at": "2026-04-07T10:02:00Z" } ], "pagination": { "limit": 20, "offset": 0, "total": 2 }}Paginating through all results
Section titled “Paginating through all results”Python
Section titled “Python”import requestsimport os
API_KEY = os.environ["CHAMELAION_API_KEY"]BASE_URL = "https://api.chamelaion.com/api"HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def list_all_requests(): """Iterate through all lip sync requests.""" offset = 0 limit = 50 all_requests = []
while True: response = requests.get( f"{BASE_URL}/v1/lipsync/requests", headers=HEADERS, params={"limit": limit, "offset": offset}, ) response.raise_for_status() data = response.json()
all_requests.extend(data["data"])
if offset + limit >= data["pagination"]["total"]: break offset += limit
return all_requestsResponse fields reference
Section titled “Response fields reference”| Field | Type | Present | Description |
|---|---|---|---|
id | string | Always | Chamelaion request UUID |
reference_id | string | If provided at creation | Your custom identifier |
status | string | Always | Current status (queued, processing, completed, failed) |
created_at | datetime | Always | When the request was created (UTC) |
started_at | datetime | After processing starts | When processing began (UTC) |
finished_at | datetime | After completion/failure | When processing ended (UTC) |
output_url | string | On completed | URL to download the generated video |
error_message | string | On failed | Description of what went wrong |