Video generation
Video is generated asynchronously: you create a job, poll until it finishes, then download the result. Generating a clip takes from tens of seconds to several minutes. Video models include veo-3.1-generate-preview, veo-3.1-fast-generate-preview, seedance-2-0, kling-v3-0, grok-imagine-video-1-5 and wan-2-6-t2v — see the models page for each one's lengths, sizes and price.
1. Create a job
curl https://api.cloakray.com/v1/videos \
-H "Authorization: Bearer $CLOAKRAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-fast-generate-preview",
"prompt": "A paper boat drifting across a quiet pond at sunrise",
"seconds": 8,
"size": "1280x720"
}'
{
"id": "video_7f3a...",
"object": "video",
"model": "veo-3.1-fast-generate-preview",
"status": "queued",
"progress": 0,
"created_at": 1767225600,
"completed_at": null,
"error": null
}
| Field | What it does |
|---|---|
model | Required. A video model. |
prompt | Required. What the video should show. |
seconds | Length. Each model offers a fixed set, for example 4, 6, 8 or 10. |
size | Output size as widthxheight, from the sizes the model offers. |
audio | false for a silent clip, on models that can do both. Silent clips are often cheaper. |
image | A first frame to animate, on models that support image-to-video. |
2. Poll the status
curl https://api.cloakray.com/v1/videos/$VIDEO_ID \
-H "Authorization: Bearer $CLOAKRAY_API_KEY"
status moves from queued to in_progress, then ends as completed or failed (or expired). Poll every 10–20 seconds with backoff rather than in a tight loop; polling is free.
3. Download the video
Once the job is completed:
curl https://api.cloakray.com/v1/videos/$VIDEO_ID/content \
-H "Authorization: Bearer $CLOAKRAY_API_KEY" \
--output video.mp4
Download it promptly and store it yourself; finished videos are not kept indefinitely. Reading the status or the content again does not charge again.
In code
const headers = { Authorization: `Bearer ${process.env.CLOAKRAY_API_KEY}`, "Content-Type": "application/json" };
const base = "https://api.cloakray.com/v1/videos";
let job = await (await fetch(base, {
method: "POST",
headers,
body: JSON.stringify({ model: "veo-3.1-fast-generate-preview", prompt: "A paper boat drifting across a pond", seconds: 8 }),
})).json();
while (job.status === "queued" || job.status === "in_progress") {
await new Promise((resolve) => setTimeout(resolve, 15_000));
job = await (await fetch(`${base}/${job.id}`, { headers })).json();
}
if (job.status !== "completed") throw new Error(job.error?.message ?? job.status);
const video = await fetch(`${base}/${job.id}/content`, { headers });
Ownership and pricing
A job ID belongs to the project whose key created it; keys from other projects get a 404. Video is priced per second of output, by resolution and by whether it has audio, and shown on each model's page. Before a job starts, your balance must cover its estimated price; a job that fails is not charged.
Use an Idempotency-Key when creating jobs, so a retried request returns the job you already started instead of paying for a second one.