OpenRouter supports video generation from text prompts (and optional reference images) via a dedicated asynchronous API. You can find the supported models, their capabilities, and pricing by filtering our model list by video output.
Adding video generation to an app? The Video Generation Cookbook breaks this workflow into step-by-step recipes for choosing a model, submitting text-to-video jobs, using images, passing provider options, and handling webhooks.
For reusable agent knowledge across projects, install the openrouter-video skill.
You can find video generation models in several ways:
Use the dedicated video models endpoint to list all available video generation models along with their supported parameters:
The response returns a data array where each model includes:
Use this endpoint to check which resolutions, aspect ratios, and passthrough parameters are supported by each model before submitting a generation request.
You can also use the output_modalities query parameter on the Models API to discover video generation models:
Visit the Models page and filter by output modalities to find models capable of video generation. Look for models that list "video" in their output modalities.
Unlike text or image generation, video generation is asynchronous because generating video takes significantly longer. The workflow is:
POST /api/v1/videosGET /api/v1/videos/{jobId}) until the status is completedGET /api/v1/videos/{jobId}/content)480p720p1080p1K2K4K16:9 — Widescreen landscape9:16 — Vertical/portrait1:1 — Square4:3 — Standard landscape3:4 — Standard portrait3:2 — Photography landscape2:3 — Photography portrait21:9 — Ultra-wide9:21 — Ultra-tallThere are two ways to provide images, each triggering a different generation mode:
frame_images — Specifies first or last frame
images for image-to-video generation. Each entry
must include a frame_type of first_frame or
last_frame.input_references — Provides style or content
reference images for reference-to-video
generation. The model uses these as visual guidance
rather than exact frames.If both fields are provided, frame_images takes
precedence and the request is treated as
image-to-video.
You can pass provider-specific options using the provider parameter. Options are keyed by provider slug, and only the options for the matched provider are forwarded:
Use the Video Models API to check which passthrough parameters each model supports via the allowed_passthrough_parameters field.
When you submit a video generation request, you receive an immediate response with the job details:
When polling the job status, the response includes additional fields as the job progresses:
Once the job status is completed, the unsigned_urls array contains URLs to download the generated video content. You can also use the content endpoint directly:
The index query parameter defaults to 0 and can be used if the model generates multiple video outputs.
Instead of polling for job status, you can receive a webhook notification when a video generation job completes. There are two ways to configure a callback URL:
callback_url in the request body. This takes priority over the workspace default.callback_url.When a job reaches a terminal state, a POST request is sent to the callback
URL with an event envelope. Each delivery also carries an
X-OpenRouter-Idempotency-Key header of the form <job_id>-<status> for
safe retry deduplication.
video.generation.completed:
video.generation.failed:
video.generation.cancelled:
video.generation.expired:
generation_id and model in data may be null when a job fails before
those values are assigned (e.g. an early validation failure).
You can configure a signing secret in your workspace settings to verify that webhook payloads are authentically from OpenRouter. When a signing secret is configured, each webhook delivery includes an X-OpenRouter-Signature header.
The signature includes a timestamp and an HMAC hash:
To verify the signature on your webhook receiver:
t) and signature hash (v1) from the header{timestamp},{raw_request_body} (joined with a comma)v1 valueUse the raw request body (the exact bytes received) for verification. Parsing and re-serializing JSON may change key ordering or number formatting, which will cause verification to fail.
failed state and handle the error field appropriatelyVideo generation is not eligible for Zero Data Retention (ZDR). Because video generation is asynchronous, the generated video output must be retained by the provider for a short period of time so that it can be retrieved after generation is complete. This temporary retention is inherent to the async polling workflow and cannot be bypassed.
If you have ZDR enforcement enabled (either via account settings or the per-request zdr parameter), video generation requests will not be routed.
Job stays in pending for a long time?
Generation failed?
error field in the poll response for detailsoutput_modalities includes "video")Model not found?
google/veo-3.1)