Loading...
Loading...
Generate videos from text prompts (and optional reference or frame images) using OpenRouter's asynchronous video generation API. Use when the user asks to create, generate, or make a video or animation from a description, animate an existing image, or turn a prompt into a short video clip.
npx skill4agent add openrouterteam/skills openrouter-videoPOST /api/v1/videoscurljqOPENROUTER_API_KEYPOST /api/v1/videos{ id, polling_url, status: "pending" }GET <polling_url>statuscompletedfailedcancelledexpirederrorGET /api/v1/videos/{id}/content?index=0resolutionaspect_ratiodurationframe_images[].frame_typecurl -sS https://openrouter.ai/api/v1/videos/models \
| jq '.data[] | select(.id == "MODEL_ID")'supported_resolutionssupported_aspect_ratiossupported_sizessupported_durations[4,6,8]supported_frame_imagesframe_typegenerate_audioseedpricing_skusallowed_passthrough_parameters#!/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.
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}'modelpromptdurationsupported_durationsresolutionaspect_ratiosize"WxH"sizegenerate_audiogenerate_audioseedseedcallback_urlframe_images[]{ type: "image_url", image_url: { url }, frame_type: "first_frame" | "last_frame" }input_references[]frame_typeframe_imagesprovider.options.<slug>.parameters.<key>urlhttps://MIME=image/png; B64=$(base64 < file.png | tr -d '\n'); url="data:${MIME};base64,${B64}"provider.options.<slug>.parametersallowed_passthrough_parameters{
"model": "google/veo-3.1",
"prompt": "a time-lapse of a flower blooming",
"provider": {
"options": {
"google-vertex": {
"parameters": {
"personGeneration": "allow",
"negativePrompt": "blurry, low quality"
}
}
}
}
}callback_urlvideo.generation.{completed,failed,cancelled,expired}X-OpenRouter-Idempotency-Key: <job_id>-<status>X-OpenRouter-Signature: t=<ts>,v1=<hmac><ts>,<raw_body>