Get the result
GET /v1/generations/{id} returns the generation. Poll it every few seconds until status is succeeded or failed. Polling is free and never counts against a rate limit.
ID=gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c
curl -s https://vidlab.ai/v1/generations/$ID \
-H "Authorization: Bearer $VIDLAB_API_KEY"import os, requests
job_id = "gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c"
r = requests.get(
f"https://vidlab.ai/v1/generations/{job_id}",
headers={"Authorization": f"Bearer {os.environ['VIDLAB_API_KEY']}"},
)
job = r.json()["data"]
print(job["status"], [o["url"] for o in job["outputs"]])const jobId = "gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c";
const res = await fetch(`https://vidlab.ai/v1/generations/${jobId}`, {
headers: { Authorization: `Bearer ${process.env.VIDLAB_API_KEY}` },
});
const { data: job } = await res.json();
console.log(job.status, job.outputs.map((o) => o.url));A finished generation:
{
"data": {
"id": "gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c",
"object": "generation",
"status": "succeeded",
"model": "seedance-2.5",
"variant": "720p",
"units": 5,
"price_usd": 1.05,
"outputs": [{ "url": "https://...", "mime": "video/mp4" }],
"created_at": "2026-11-01T18:04:11.000Z",
"finished_at": "2026-11-01T18:06:02.000Z"
}
}- Poll every 3 seconds for images and every 5 to 10 for video. VidLab asks the provider on its own schedule, so polling faster does not finish sooner.
GET /v1/jobs/{id},/v1/jobs/{id}/statusand/v1/jobs/{id}/resultreturn the same answer.- Another account's id answers
404 generation_not_found.
Download the file
The files are in outputs. Download them with your key, so you never depend on a link that expires: GET /v1/generations/{id}/content is the first file, /content/2 the second, and so on. The answer redirects to the stored file, so follow redirects (curl -L; fetch and requests do by default).
curl -sL https://vidlab.ai/v1/generations/$ID/content \
-H "Authorization: Bearer $VIDLAB_API_KEY" -o out.mp4import os, requests
job_id = "gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c"
file = requests.get(
f"https://vidlab.ai/v1/generations/{job_id}/content",
headers={"Authorization": f"Bearer {os.environ['VIDLAB_API_KEY']}"},
)
open("out.mp4", "wb").write(file.content)import { writeFile } from "node:fs/promises";
const jobId = "gen_4Fq9xT2mLr7Kd1sV8bN3pZ0c";
const file = await fetch(`https://vidlab.ai/v1/generations/${jobId}/content`, {
headers: { Authorization: `Bearer ${process.env.VIDLAB_API_KEY}` },
});
await writeFile("out.mp4", Buffer.from(await file.arrayBuffer()));- A generation that is not finished answers
409 not_ready(withRetry-After), a failed one409 generation_failed, and a number past the last file404 output_not_found. - The
urlinoutputsis a signed link that lasts 6 hours; each poll returns a working one. The files themselves are kept for 30 days after the generation finished (outputs_kept_until). Copy files you want to keep longer to your own storage. - An image call with
nabove 1 returns one output per image.
List generations
GET /v1/generations returns your generations, newest first, with the same key. It is free and never rate limited. Use it for a task log, or to find an id you lost.
| Query | Values | What it does |
|---|---|---|
limit | 1 to 100 (default 25) | How many generations in the page. |
starting_after | A generation id | The next page: send the last id of the page before. |
status | queued, running, succeeded, failed | Only generations in that status. |
model | A model id | Only that model's generations. |
curl -s "https://vidlab.ai/v1/generations?limit=10&status=succeeded" \
-H "Authorization: Bearer $VIDLAB_API_KEY"The answer is { "object": "list", "data": [generation, ...], "has_more": false }. When has_more is true, call again with starting_after set to the last id. A bad query value answers 400 (invalid_limit, invalid_status, invalid_model, invalid_starting_after).