openrouter-video

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenRouter Video

OpenRouter Video

Generate videos via OpenRouter's async
POST /api/v1/videos
using
curl
+
jq
. Requires
OPENROUTER_API_KEY
(get one at https://openrouter.ai/keys). If unset, stop and ask.
通过
curl
+
jq
调用OpenRouter的异步接口
POST /api/v1/videos
生成视频。需要
OPENROUTER_API_KEY
(可在https://openrouter.ai/keys获取)。如果未设置该密钥,请停止操作并询问用户。

The three steps

三个步骤

Video generation is async: submit → poll → download. A single request can't return the video because generation takes 30s–a few minutes. Tell the user the job was submitted so they know the delay is expected.
  1. POST /api/v1/videos
    { id, polling_url, status: "pending" }
  2. GET <polling_url>
    every ~30s until
    status
    is
    completed
    (terminal failures:
    failed
    ,
    cancelled
    ,
    expired
    — surface the
    error
    field verbatim)
  3. GET /api/v1/videos/{id}/content?index=0
    with the auth header → MP4 bytes
视频生成是异步流程:提交任务 → 轮询状态 → 下载视频。单次请求无法直接返回视频,因为生成过程需要30秒到数分钟。请告知用户任务已提交,让他们知晓延迟是正常现象。
  1. 调用
    POST /api/v1/videos
    → 返回
    { id, polling_url, status: "pending" }
  2. 每隔约30秒调用
    GET <polling_url>
    ,直到
    status
    变为
    completed
    (终端失败状态:
    failed
    cancelled
    expired
    — 直接展示
    error
    字段的内容)
  3. 携带认证头调用
    GET /api/v1/videos/{id}/content?index=0
    → 获取MP4字节数据

Pick parameters from the models endpoint, don't guess

从模型端点获取参数,不要自行猜测

resolution
,
aspect_ratio
,
duration
, and
frame_images[].frame_type
are per-model. Before the first submit for a new model (or whenever the user asks for something specific), fetch the model's capabilities and only send values from the returned sets:
bash
curl -sS https://openrouter.ai/api/v1/videos/models \
  | jq '.data[] | select(.id == "MODEL_ID")'
Fields on each model worth knowing:
supported_resolutions
,
supported_aspect_ratios
,
supported_sizes
,
supported_durations
(often discrete like
[4,6,8]
, not a range),
supported_frame_images
(which
frame_type
values are accepted),
generate_audio
and
seed
(capability bools),
pricing_skus
, and
allowed_passthrough_parameters
. An out-of-set value returns a 400, so validate client-side.
resolution
aspect_ratio
duration
frame_images[].frame_type
参数因模型而异。在首次提交新模型的任务前(或用户要求特定参数时),先获取该模型的能力范围,仅发送返回集合内的有效值:
bash
curl -sS https://openrouter.ai/api/v1/videos/models \
  | jq '.data[] | select(.id == "MODEL_ID")'
每个模型需要关注的字段包括:
supported_resolutions
supported_aspect_ratios
supported_sizes
supported_durations
(通常是离散值,如
[4,6,8]
,而非范围)、
supported_frame_images
(支持的
frame_type
值)、
generate_audio
seed
(布尔型能力标识)、
pricing_skus
以及
allowed_passthrough_parameters
。若发送集合外的值会返回400错误,因此需在客户端验证参数。

Full workflow (drop-in)

完整工作流(可直接使用)

bash
#!/usr/bin/env bash
set -euo pipefail

PROMPT="a golden retriever playing fetch on a sunny beach"
MODEL="google/veo-3.1"
OUTPUT="video-$(date +%Y%m%d-%H%M%S).mp4"
bash
#!/usr/bin/env bash
set -euo pipefail

PROMPT="a golden retriever playing fetch on a sunny beach"
MODEL="google/veo-3.1"
OUTPUT="video-$(date +%Y%m%d-%H%M%S).mp4"

Build payload — extend with resolution/aspect_ratio/duration/etc. as needed.

Build payload — extend with resolution/aspect_ratio/duration/etc. as needed.

payload=$(jq -n --arg model "$MODEL" --arg prompt "$PROMPT"
'{model: $model, prompt: $prompt}')
submit=$(curl -sS -X POST https://openrouter.ai/api/v1/videos
-H "Authorization: Bearer $OPENROUTER_API_KEY"
-H "Content-Type: application/json"
-d "$payload")
poll_url=$(echo "$submit" | jq -r '.polling_url') echo "Submitted $(echo "$submit" | jq -r '.id')" >&2
while :; do sleep 30 resp=$(curl -sS "$poll_url" -H "Authorization: Bearer $OPENROUTER_API_KEY")

Avoid the name
status
— zsh treats it as read-only.

st=$(echo "$resp" | jq -r '.status') echo "Status: $st" >&2 case "$st" in completed) break ;; failed|cancelled|expired) echo "Generation $st: $(echo "$resp" | jq -r '.error // "unknown"')" >&2 exit 1 ;; esac done
curl -sS -L "$(echo "$resp" | jq -r '.unsigned_urls[0]')"
-H "Authorization: Bearer $OPENROUTER_API_KEY"
--output "$OUTPUT"
echo "$resp" | jq --arg out "$(realpath "$OUTPUT")"
'{job_id: .id, generation_id, video_saved: $out, usage}'
undefined
payload=$(jq -n --arg model "$MODEL" --arg prompt "$PROMPT"
'{model: $model, prompt: $prompt}')
submit=$(curl -sS -X POST https://openrouter.ai/api/v1/videos
-H "Authorization: Bearer $OPENROUTER_API_KEY"
-H "Content-Type: application/json"
-d "$payload")
poll_url=$(echo "$submit" | jq -r '.polling_url') echo "Submitted $(echo "$submit" | jq -r '.id')" >&2
while :; do sleep 30 resp=$(curl -sS "$poll_url" -H "Authorization: Bearer $OPENROUTER_API_KEY")

Avoid the name
status
— zsh treats it as read-only.

st=$(echo "$resp" | jq -r '.status') echo "Status: $st" >&2 case "$st" in completed) break ;; failed|cancelled|expired) echo "Generation $st: $(echo "$resp" | jq -r '.error // "unknown"')" >&2 exit 1 ;; esac done
curl -sS -L "$(echo "$resp" | jq -r '.unsigned_urls[0]')"
-H "Authorization: Bearer $OPENROUTER_API_KEY"
--output "$OUTPUT"
echo "$resp" | jq --arg out "$(realpath "$OUTPUT")"
'{job_id: .id, generation_id, video_saved: $out, usage}'
undefined

Parameters

参数说明

Required:
model
,
prompt
. Common optional fields:
  • duration
    (int) — must be one of the model's
    supported_durations
    .
  • resolution
    (string) /
    aspect_ratio
    (string) /
    size
    (string,
    "WxH"
    ) —
    size
    is interchangeable with resolution + aspect_ratio.
  • generate_audio
    (bool) — only meaningful if the model's
    generate_audio
    capability is true.
  • seed
    (int) — honored only if the model's
    seed
    capability is true.
  • callback_url
    (HTTPS) — webhook instead of polling.
  • frame_images[]
    — image-to-video; each entry is
    { type: "image_url", image_url: { url }, frame_type: "first_frame" | "last_frame" }
    .
  • input_references[]
    — reference-to-video (style guidance); same entry shape, no
    frame_type
    . If both arrays are present,
    frame_images
    wins.
  • provider.options.<slug>.parameters.<key>
    — provider passthrough, see below.
Image
url
can be a public
https://
URL or a local-file data URL:
MIME=image/png; B64=$(base64 < file.png | tr -d '\n'); url="data:${MIME};base64,${B64}"
.
必填参数:
model
prompt
。常见可选字段:
  • duration
    (整数)—— 必须是模型
    supported_durations
    中的值。
  • resolution
    (字符串)/
    aspect_ratio
    (字符串)/
    size
    (字符串,格式为
    "WxH"
    )——
    size
    与resolution + aspect_ratio可互换使用。
  • generate_audio
    (布尔值)—— 仅当模型的
    generate_audio
    能力为true时有效。
  • seed
    (整数)—— 仅当模型的
    seed
    能力为true时生效。
  • callback_url
    (HTTPS)—— 使用webhook替代轮询。
  • frame_images[]
    —— 图像转视频;每个条目格式为
    { type: "image_url", image_url: { url }, frame_type: "first_frame" | "last_frame" }
  • input_references[]
    —— 参考图转视频(风格引导);条目格式相同,但无
    frame_type
    。若同时存在两个数组,
    frame_images
    优先级更高。
  • provider.options.<slug>.parameters.<key>
    —— 供应商透传参数,详见下文。
图像
url
可以是公开的
https://
链接,或本地文件的data URL:
MIME=image/png; B64=$(base64 < file.png | tr -d '\n'); url="data:${MIME};base64,${B64}"

Provider passthrough

供应商透传参数

Provider-specific params go under
provider.options.<slug>.parameters
. The allowed keys for a given model are listed (flat) in
allowed_passthrough_parameters
on the models endpoint — but the meaning, value range, and required combinations come from the upstream provider's API docs (Google Vertex, Alibaba Dashscope, Kwai, ByteDance Volc Engine, MiniMax, OpenAI, etc.). Read the upstream docs before using an unfamiliar key; casing conventions differ between providers (Google/OpenAI use camelCase, most others use snake_case).
Example:
json
{
  "model": "google/veo-3.1",
  "prompt": "a time-lapse of a flower blooming",
  "provider": {
    "options": {
      "google-vertex": {
        "parameters": {
          "personGeneration": "allow",
          "negativePrompt": "blurry, low quality"
        }
      }
    }
  }
}
供应商特定参数需放在
provider.options.<slug>.parameters
下。特定模型允许的键会在模型端点的
allowed_passthrough_parameters
中列出(扁平化结构)—— 但参数的含义、取值范围和必填组合需参考上游供应商的API文档(如Google Vertex、Alibaba Dashscope、Kwai、ByteDance Volc Engine、MiniMax、OpenAI等)。使用不熟悉的参数前请阅读上游文档;不同供应商的命名规范不同(Google/OpenAI使用驼峰式,多数其他供应商使用蛇形命名)。
示例:
json
{
  "model": "google/veo-3.1",
  "prompt": "a time-lapse of a flower blooming",
  "provider": {
    "options": {
      "google-vertex": {
        "parameters": {
          "personGeneration": "allow",
          "negativePrompt": "blurry, low quality"
        }
      }
    }
  }
}

Webhooks (optional)

Webhook(可选)

Pass
callback_url
(HTTPS) in the submit body. On terminal state, OpenRouter POSTs a
video.generation.{completed,failed,cancelled,expired}
event. Each delivery carries
X-OpenRouter-Idempotency-Key: <job_id>-<status>
. If a signing secret is configured on the workspace, verify
X-OpenRouter-Signature: t=<ts>,v1=<hmac>
— HMAC-SHA256 of
<ts>,<raw_body>
with the secret, reject timestamps older than ~5 minutes.
在提交请求的body中传入
callback_url
(HTTPS)。当任务进入终端状态时,OpenRouter会POST一个
video.generation.{completed,failed,cancelled,expired}
事件。每次推送都会携带
X-OpenRouter-Idempotency-Key: <job_id>-<status>
。若工作区配置了签名密钥,需验证
X-OpenRouter-Signature: t=<ts>,v1=<hmac>
— 使用密钥对
<ts>,<raw_body>
进行HMAC-SHA256加密,拒绝时间戳超过约5分钟的请求。

References

参考资料

Video generation is not ZDR-eligible because the provider must temporarily retain the output for the async download step.
视频生成不支持ZDR(零数据残留),因为供应商必须临时保留输出文件以支持异步下载步骤。