A plain REST interface to AI video models. Create a job, poll it, download the MP4. Pin a provider or let the router pick the cheapest healthy host.
Send your key as a bearer token. Keys can carry a monthly spend cap, rate limits and a per-key model allow-list.
Authorization: Bearer llmr_sk_live_...
POST /v1/videos — returns 202 with a job.
curl https://videorouter.sh/api/v1/videos \
-H "Authorization: Bearer $VIDEOROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "bytedance/seedance-2.0-mini", "prompt": "a paper airplane gliding over a city", "duration_secs": 5}'
# -> {"id": "video_...", "status": "queued"}
curl https://videorouter.sh/api/v1/videos/$ID -H "Authorization: Bearer $VIDEOROUTER_API_KEY"import time, requests
H = {"Authorization": "Bearer llmr_sk_live_..."}
job = requests.post("https://videorouter.sh/api/v1/videos", headers=H, json={
"model": "bytedance/seedance-2.0-mini", "prompt": "a paper airplane gliding over a city", "duration_secs": 5}).json()
while job["status"] not in ("completed", "failed"):
time.sleep(5)
job = requests.get(f"https://videorouter.sh/api/v1/videos/{job['id']}", headers=H).json()
print(job["data"][0]["url"] if job["status"] == "completed" else job["error"])const H = { Authorization: "Bearer llmr_sk_live_...", "Content-Type": "application/json" };
let job = await (await fetch("https://videorouter.sh/api/v1/videos", { method: "POST", headers: H,
body: JSON.stringify({ model: "bytedance/seedance-2.0-mini", prompt: "a paper airplane gliding over a city", duration_secs: 5 }) })).json();
while (!["completed", "failed"].includes(job.status)) {
await new Promise(r => setTimeout(r, 5000));
job = await (await fetch(`https://videorouter.sh/api/v1/videos/${job.id}`, { headers: H })).json();
}
console.log(job.data?.[0]?.url ?? job.error);| Field | Type | Description |
|---|---|---|
model | string | Model id, optionally with a host suffix (model/host) to prefer a provider. |
prompt | string | Text prompt. Required for most models. |
duration_secs | number | Seconds of output. Snapped to a value the model supports; billing uses the snapped value. |
aspect_ratio / resolution | string | e.g. 16:9, 720p. Unsupported combinations are ignored (model default), never a 400. |
start_image_url | string | Image-to-video: public https URL or base64 data URI. |
input_references | array | Reference-to-video: image entries (model-dependent cap). |
input_video_url | string | Video editing: an existing clip to modify. Needs a prompt describing the edit. |
provider / failover | object | Provider preferences; failover.on_timeout_sec resubmits to the next host (both attempts billed). |
GET /v1/videos/{id} — poll until status is completed or failed. Polling is not billed. On success data[0].url is the file.
GET /v1/videos/models — every valid model id (ids only). For prices and hosts use the price tables.
All errors share the OpenAI-style envelope {"error": {"message", "type", "code"}}.
| Status | Type / code | Meaning |
|---|---|---|
| 400 | invalid_request_error | Missing prompt, unknown model id, bad parameters. Don’t retry. |
| 401 | invalid_api_key | Missing, malformed, revoked or expired key. |
| 402 | insufficient_credits / spend_cap_exceeded | Balance empty or monthly cap hit. Don’t retry. |
| 403 | model_not_allowed | Model not in this key’s allow-list. |
| 429 | rpm_limit / tpm_limit | Rate limited. Wait Retry-After, retry. |
| 5xx | upstream_error | All candidate hosts failed. Retry with backoff; not billed. |
Charged once at creation from the requested (snapped) duration; polling is free; jobs that end failed because every upstream host failed are not billed. VideoRouter adds a flat 2% platform fee on image and video generation.
You don't need one — it's a REST API with a simple job lifecycle. The quickstart shows curl, Python and JavaScript.
Poll GET /v1/videos/{id} until status is completed or failed. Polling is not billed.
Unpinned requests retry another host serving the same model. Pinned requests fail fast, by design.
Yes — keys support monthly caps, rate limits and per-key model allow-lists.
VideoRouter puts it next to dozens of other video and image models behind one API key, so you can compare providers, prices and fail over automatically. Compare providers on VideoRouter →