How to Generate AI Videos with an API
An AI video generation API tutorial: submit async jobs to Veo, Seedance, and KLING through one OpenAI-compatible endpoint, poll or receive signed webhooks, download the MP4, and keep per-second costs visible.

Video models don't respond in milliseconds — a single clip can take minutes to render, and every provider handles the waiting differently. Google Vertex uses long-running operations, ByteDance uses task polling, AtlasCloud uses prediction endpoints. Building against three job systems to compare three models is a bad afternoon.
LLM Gateway wraps all of them in one asynchronous, OpenAI-compatible AI video generation API: POST /v1/videos submits the job, GET /v1/videos/{id} reports progress, and GET /v1/videos/{id}/content streams the finished MP4 — for every video model in the catalog. Browse the current list on the models page with the video filter.
Submit a job
1curl -X POST "https://api.llmgateway.io/v1/videos" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "veo-3.1-generate-preview",6 "prompt": "A cinematic aerial shot flying above a rainforest waterfall at sunrise",7 "seconds": 8,8 "size": "1920x1080"9 }'1curl -X POST "https://api.llmgateway.io/v1/videos" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "veo-3.1-generate-preview",6 "prompt": "A cinematic aerial shot flying above a rainforest waterfall at sunrise",7 "seconds": 8,8 "size": "1920x1080"9 }'The response comes back immediately with a job id:
1{2 "id": "v_123",3 "object": "video",4 "model": "veo-3.1-generate-preview",5 "status": "queued",6 "progress": 0,7 "created_at": 1753500000,8 "completed_at": null,9 "error": null10}1{2 "id": "v_123",3 "object": "video",4 "model": "veo-3.1-generate-preview",5 "status": "queued",6 "progress": 0,7 "created_at": 1753500000,8 "completed_at": null,9 "error": null10}Three fields are required: model, prompt, and seconds. Optional fields include size (widthxheight), audio (default true), first/last frame images for image-to-video, and reference images, videos, or audio on models that support them. Video generation requires at least $1.00 of available organization credits before the job is submitted.
Pick a model, duration, and resolution
Each model supports specific sizes and durations — requests outside them return a 400 instead of silently rendering something else:
| Model family | Sizes | Durations | Price (720p/1080p, with audio) |
|---|---|---|---|
| Veo 3.1 | 720p, 1080p, 4K (portrait too) | 4, 6, 8, 10 | $0.40/s (1080p) |
| Veo 3.1 Fast | 720p, 1080p, 4K | 4, 6, 8, 10 | $0.15/s (1080p) |
| Seedance 2.0 | 720p, 1080p | 4–15 | $0.15/s / $0.34/s |
| Seedance 2.0 Mini | 480p, 720p | 4–15 | $0.04/s / $0.08/s |
| KLING v3.0 | 720p, 1080p, 4K | 5, 10 | $0.13/s / $0.17/s |
Billing is per second of generated video, so an 8-second 1080p Veo 3.1 clip costs about $3.20, while the same clip on Seedance 2.0 Mini at 720p costs about $0.60. The video generation docs carry the full per-model price and size tables.
Poll for completion and download
1curl "https://api.llmgateway.io/v1/videos/v_123" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY"1curl "https://api.llmgateway.io/v1/videos/v_123" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY"Statuses move through queued → in_progress → completed (or failed). Once complete, stream the bytes:
1curl "https://api.llmgateway.io/v1/videos/v_123/content" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 --output video.mp41curl "https://api.llmgateway.io/v1/videos/v_123/content" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 --output video.mp4Skip polling with signed webhooks
Polling works, but for production the gateway can call you. Pass callback_url and callback_secret when creating the job:
1curl -X POST "https://api.llmgateway.io/v1/videos" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "veo-3.1-fast-generate-preview",6 "prompt": "A slow-motion close-up of waves crashing against black volcanic rock",7 "seconds": 8,8 "callback_url": "https://example.com/webhooks/video",9 "callback_secret": "whsec_your_secret_here"10 }'1curl -X POST "https://api.llmgateway.io/v1/videos" \2 -H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "veo-3.1-fast-generate-preview",6 "prompt": "A slow-motion close-up of waves crashing against black volcanic rock",7 "seconds": 8,8 "callback_url": "https://example.com/webhooks/video",9 "callback_secret": "whsec_your_secret_here"10 }'You get a video.completed or video.failed event with retries and exponential backoff. Every delivery is signed with HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{body} so you can verify it server-side:
1import { createHmac, timingSafeEqual } from "node:crypto";2
3function verifyWebhook(4 body: string,5 webhookId: string,6 webhookTimestamp: string,7 webhookSignature: string,8 secret: string,9) {10 const expected = createHmac("sha256", secret)11 .update(`${webhookId}.${webhookTimestamp}.${body}`)12 .digest("base64");13
14 return timingSafeEqual(15 Buffer.from(expected),16 Buffer.from(webhookSignature.replace(/^v1,/, "")),17 );18}1import { createHmac, timingSafeEqual } from "node:crypto";2
3function verifyWebhook(4 body: string,5 webhookId: string,6 webhookTimestamp: string,7 webhookSignature: string,8 secret: string,9) {10 const expected = createHmac("sha256", secret)11 .update(`${webhookId}.${webhookTimestamp}.${body}`)12 .digest("base64");13
14 return timingSafeEqual(15 Buffer.from(expected),16 Buffer.from(webhookSignature.replace(/^v1,/, "")),17 );18}Image-to-video and reference-guided clips
Two more modes beyond text-to-video:
- First/last frame: pass
image(and optionallylast_frame) to animate between frames — supported on Seedance 2.0, KLING v3.0, and Veo 3.1. - Omni-reference (Seedance 2.0): pass up to three
reference_images,reference_videos, andreference_audiosto drive subject, motion, and sound; the prompt becomes a light instruction like "adapt this to show more detail".
Frame inputs and reference inputs can't be combined in one request, and reference video/audio must be HTTPS URLs the provider can fetch.
Watch the spend
Video is the most expensive modality you'll route, so treat cost as a first-class output: every job is logged with its per-second price, the Activity page breaks out video output costs, and API key spending limits put a hard cap on how much a runaway batch job can burn.
Frequently Asked Questions
How long does AI video generation take?
Minutes, not seconds — depending on the model, duration, and resolution. That's why the API is asynchronous: submit, then poll or take a webhook. 4K jobs stay in_progress until the upscaled output is ready.
Which video model is cheapest for prototyping?
Prototype on a low-priced tier like Seedance 2.0 Mini at 480p or 720p, then re-render the winning prompt on a premium model at 1080p — same request body, different model and size.
Can I generate videos without writing code first?
Yes — the Video Studio in Lounge runs the same models with resolution, duration, and audio controls in the browser.
Get started:
- Try LLM Gateway free — one key for every video model
- Video generation docs — sizes, durations, prices, and callbacks
- How to generate images with the API — the synchronous counterpart