Async Jobs

Beta
Submit video generation as background jobs and poll for results

The async API (V2) lets you submit a generation request and poll for its response. The result is downloadable using a URL available when the job completes. This is the recommended approach for production workloads, as it avoids the connection timeouts that can affect long-running sync requests.

Lifecycle

  1. Submit. POST to an async endpoint (/v2/{endpoint}) with your generation parameters. The response is 202 Accepted with a job ID.
  2. Poll. GET /v2/{endpoint}/{id} every few seconds until the status field is completed or failed.
  3. Download. When status is completed, the result object contains one or more URLs pointing to the generated output files.

Status values

StatusMeaning
pendingJob is queued.
processingGeneration is running.
completedJob finished successfully. result contains output URLs.
failedJob failed. error describes why.

completed and failed are terminal — stop polling when you see either.

Result format

The result object on a completed job is a map of output labels to URLs. The available keys depend on the endpoint — most video endpoints return video_url, while video-to-video-hdr returns exr_frames_url. Check each endpoint’s reference for the exact shape.

1{
2 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
3 "status": "completed",
4 "created_at": "2026-01-15T10:00:00.000Z",
5 "completed_at": "2026-01-15T10:02:30.000Z",
6 "result": {
7 "video_url": "https://storage.googleapis.com/example/video.mp4"
8 }
9}

Polling guidance

  • Poll every 5 seconds. Shorter intervals add load without meaningfully reducing latency.
  • Treat transient HTTP errors (5xx, network failures) as retryable — your poll loop should retry with backoff rather than giving up. The examples below omit error handling for brevity.
  • A 404 means the job doesn’t exist or has expired (see retention below).

Retention

Job status and output URLs are available for 24 hours after the job reaches a terminal state. After that, GET /v2/{endpoint}/{id} returns 404. Download or re-host outputs before that window expires.

Error handling

Errors appear in two places but use the same { type, message } shape:

  • HTTP errors on POST or GET requests — validation, auth, rate limits, etc.
  • Job failures inside the status response when a job fails during processing.

Your error handling logic can use the same type checks (e.g., content_filtered_error, insufficient_funds_error) regardless of where the error appears. See Error Handling for the full list.

Example

A complete submit → poll → download loop:

1import requests
2import time
3
4api_key = "YOUR_API_KEY"
5headers = {"Authorization": f"Bearer {api_key}"}
6
7# Submit
8job = requests.post(
9 "https://api.ltx.video/v2/text-to-video",
10 headers={**headers, "Content-Type": "application/json"},
11 json={
12 "prompt": "A majestic eagle soaring through clouds at sunset",
13 "model": "ltx-2-3-pro",
14 "duration": 8,
15 "resolution": "1920x1080",
16 },
17).json()
18
19# Poll
20while True:
21 status = requests.get(
22 f"https://api.ltx.video/v2/text-to-video/{job['id']}",
23 headers=headers,
24 ).json()
25 if status["status"] in ("completed", "failed"):
26 break
27 time.sleep(5)
28
29if status["status"] == "failed":
30 raise RuntimeError(status["error"]["message"])
31
32# Download
33video = requests.get(status["result"]["video_url"])
34with open("video.mp4", "wb") as f:
35 f.write(video.content)