--- title: Polling & Request Status | Chamelaion description: 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 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 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 Terminal window ``` curl https://api.chamelaion.com/api/v1/lipsync/requests/6f82a2d8-a6d4-4e8a-a0fa-e8b09823a2d8 \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` ### By reference ID Terminal window ``` curl https://api.chamelaion.com/api/v1/lipsync/requests/my-custom-reference \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` ### 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) ``` { "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 Here’s the recommended polling pattern with exponential backoff: ### Python ``` import requests import time import 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 ``` async function waitForCompletion( requestId: string, timeoutMs = 600_000 ): Promise> { 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`); } ``` Start with a 2-second polling interval and increase gradually up to 15 seconds. This balances responsiveness with rate limit usage. ## List all requests Use `GET /v1/lipsync/requests` to retrieve a paginated list of your lip sync requests. ### Basic listing Terminal window ``` curl "https://api.chamelaion.com/api/v1/lipsync/requests" \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` ### With pagination Terminal window ``` curl "https://api.chamelaion.com/api/v1/lipsync/requests?limit=10&offset=20" \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` ### Filter by reference ID Terminal window ``` curl "https://api.chamelaion.com/api/v1/lipsync/requests?reference_id=batch-2026-04" \ -H "Authorization: Bearer $CHAMELAION_API_KEY" ``` ### 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 ``` { "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 ### Python ``` import requests import 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_requests ``` ## 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 |