API reference
Every route below, except API key management, is for sending model requests, and requires
Authorization: Bearer llmr_sk_<env>_… —
see Authentication.
GET /v1/balance returns the key's wallet for low-balance alerts:
{"balance_usd", "available_usd", "held_usd", "held_release_at"}.
Alert on available_usd — it excludes in-flight job reservations and unreleased ACH holds, the number a new request is checked against. Unbilled.
Pricing
Two read-only calls tell you what something costs before you send it. Neither reserves credits, calls a provider, or is billed.
GET/v1/models
Every row carries a pricing object — the model's list price, the same numbers as
the /models page. One shape for every model type:
unit says what each number in rates is per, and
rates is keyed by whatever the price varies on (a video's resolution tier, an image's
size/quality, token direction). "*" means the same for every option.
The platform_fee_rate is billed on top: you pay rate × (1 + platform_fee_rate).
pricing is null for auto (it routes per request) and for a model with no published price yet.
{
"id": "fal/seedance-2.0",
"object": "model",
"type": "video",
"endpoint": "/v1/videos",
"pricing": {
"currency": "USD",
"unit": "second",
"rates": { "480p": 0.1345, "720p": 0.3034, "1080p": 0.682, "4k": 1.5552 },
"platform_fee_rate": 0.025
}
}
rates is keyed by1m_tokenschat (input, output, cache_read, cache_write), embeddings, and token-billed image / speech modelssecondvideo, lip sync, face swap, avatars, sound effects, live video — keyed by resolution tier (avatars: avatar_type/resolution; live video: standard / fast, plus world_setup_fee and min_billed_seconds where a model has them)clipvideo priced per finished clip, keyed by length ("6s", "10s")imageimages — "*", or size/quality (e.g. "1k/standard")minute · song · modeltranscription, music, and 3D (base plus an addons object, or one rate per texture_quality)1m_characterstext-to-speechmegapixel · variableper-megapixel images; and rows whose price depends on the input you send (upscalers) — use the estimate belowPOST/v1/pricing/estimate
Send the same JSON you would send to the real endpoint, plus type (or endpoint,
e.g. "/v1/videos") saying which one — and get the expected total back. If you leave both out, the
type is inferred from model when it is unambiguous.
Request
curl https://videorouter.sh/v1/pricing/estimate \
-H "Authorization: Bearer $VIDEOROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "video", "model": "fal/seedance-2.0", "duration_secs": 8, "resolution": "720p"}'
Example response
{
"object": "pricing.estimate",
"type": "video",
"model": "fal/seedance-2.0",
"currency": "USD",
"estimated_cost_usd": 2.48788,
"max_cost_usd": 2.48788,
"breakdown": { "subtotal_usd": 2.4272, "platform_fee_usd": 0.06068, "platform_fee_rate": 0.025 },
"pricing": {
"currency": "USD",
"unit": "second",
"rates": { "480p": 0.1345, "720p": 0.3034, "1080p": 0.682, "4k": 1.5552 },
"platform_fee_rate": 0.025
},
"assumptions": { "duration_secs": 8.0, "resolution": "720p", "aspect_ratio": "16:9" },
"notes": []
}
estimated_cost_usdWhat the request is expected to cost, platform fee included — the price on the cheapest host that will serve it. null when the price is only known after the call runs (token-billed images, some music models); notes says why.max_cost_usdThe most automatic failover could reach if cheaper hosts are down. Equal to the estimate when there is nothing pricier to fall back to.assumptionsEverything the price depended on that the request did not state outright — the resolution tier a default resolved to, the output tokens assumed. Never silent.notesPlain-English caveats (“billed on the tokens actually used”, “priced at the model's 30s maximum input”).What to send, per type
chatmessages (sized at ~4 characters per token) or input_tokens; output_tokens or max_tokens (otherwise 4096 is assumed). Billed on real usage afterwards.videoduration_secs, resolution, aspect_ratio, n, draft, task_type, auto_upscale, input_references / input_video_references (+ reference_video_secs). Editing or upscaling: input_video_url with input_video_secs (upscalers also input_width / input_height).imagen, size or resolution + aspect_ratio, quality. A model priced per tier (1k, 2k, …) takes the tier as resolution.lipsync · face_swap · avataraudio_secs (lip sync, avatar), video_secs (face swap), resolution; an avatar can send its script instead of audio_secs.speech · transcription · embeddingspeech: input (the text); transcription: duration_secs (or minutes); embedding: input or input_tokens.music · sfx · mesh · live_videomusic / sfx: duration; 3D: the add-on flags (texture_quality, textured, …); live video: max_duration_seconds, speed.An estimate that cannot be priced honestly (an upscaler without its clip facts, a transcription without a length, auto) is a 400 with code: "cannot_estimate" and a message naming the missing field. An estimate is a quote, not a cap: chat, token-billed and settle-at-cost models are charged on what they actually use.
Chat completions
| Endpoint | Description |
|---|---|
| POST /v1/chat/completions | OpenAI-compatible chat completions; model:"auto" routes, a slug pins — streaming, tools, automatic fallback |
| POST /v1/route | routing decision only — no upstream call, no charge |
| GET /v1/models | every model on every endpoint (chat, images, video, lip sync, face swap, 3D, music, speech, embeddings, live video), each with its type, endpoint and pricing (per-resolution / per-option rates — see Pricing); filter with ?type=chat. Chat rows include the auto pseudo-model and honour your key's allowlist |
| POST /v1/pricing/estimate | what one request to any endpoint will cost, before you send it — no upstream call, no charge. See Pricing |
Full request/response detail: Models & routing, Streaming, Tool calling. Full parameters & example responses: Chat completions API reference →
Image generation is also reachable here — pass modalities: ["image", "text"] to get a generated image back on message.images, billed the same rate as /v1/images below. See image output in chat completions.
Spoken audio output too — pass modalities: ["audio", "text"] to a gpt-audio model to get a reply back on message.audio. See audio output in chat completions.
Embeddings
A provider passthrough endpoint kept for drop-in SDK compatibility — not part of the chat/routing surface.
| Endpoint | Description |
|---|---|
| POST /v1/embeddings | OpenAI-compatible embeddings, billed the same as chat (provider cost + 2.5%) |
Full parameters & example responses: Embeddings API reference →
Images
| Endpoint | Description |
|---|---|
| POST /v1/images | unified text-to-image generation and image-to-image editing (pass input_references) — one endpoint for both, billed per image |
| GET /v1/images/models | live list of every valid model slug for POST /v1/images — bare ids only, no price/capability breakdown (see /models for that); unbilled |
Full guide: image generation → Full parameters & example responses: Images API reference →
Uploads
A helper for any caller — images, video, lip sync, face swap — that has raw file bytes rather than an
already-public URL to pass as a reference (input_references,
start_image_url,
input_video_url, etc.). A base64
data: URI works directly on those
fields too and skips this call entirely — use it for small files; use this endpoint when that would blow
past a request-body-size limit.
| Endpoint | Description |
|---|---|
| POST /v1/uploads | multipart file upload (image ≤10 MB, audio ≤20 MB, video ≤50 MB); returns a presigned url valid for 30 minutes — stage it, then immediately reference it in the same session's generate call; unbilled, not durable storage |
Audio
| Endpoint | Description |
|---|---|
| POST /v1/audio/speech | text-to-speech; returns raw audio, billed per input character (per-token for gpt-4o-mini-tts and the Gemini TTS family) |
| POST /v1/audio/transcriptions | speech-to-text, billed per minute of real audio duration (per-token for Gemini 3.5 Transcribe) |
| POST /v1/audio/music | text-to-music (Google Lyria); returns raw audio, billed flat per generated song |
| GET /v1/audio/music/models | live list of every valid model slug for POST /v1/audio/music (also GET /v1/audio/sfx/models for POST /v1/audio/sfx); unbilled |
Full guide: text-to-speech → · Full guide: speech-to-text → Full parameters & example responses: Audio API reference →
Realtime
Full-duplex voice, one WebSocket for GPT Realtime (OpenAI/Azure), Grok Voice (xAI), Gemini Live (Google),
and GPT Live 1 — a ?model= change,
not a different endpoint.
| Endpoint | Description |
|---|---|
| WS /v1/realtime | open a WebSocket, pick a model with ?model=, exchange that model's own event frames — billed per token (GPT Realtime/Gemini Live) or per session-minute (Grok Voice, GPT Realtime Translate/Whisper, GPT Live 1) |
Full guide: Realtime guide → Full parameters & example responses: Realtime API reference →
Video
| Endpoint | Description |
|---|---|
| POST /v1/videos | submit a video generation job — text-to-video, or image-to-video (pass start_image_url)/reference-to-video (pass input_references/input_video_references/input_audio_references) on supporting models; async, returns a video id immediately; billed per requested second at creation time |
| GET /v1/videos/models | live list of every valid model slug for POST /v1/videos — bare ids only, no price/capability breakdown (see /models for that); unbilled |
| GET /v1/videos/{id} | poll status; the finished video URL is included once status is completed |
Full guide: video generation → Full parameters & example responses: Video API reference → — also see Motion control → for Kling v3.0 Motion Control's character-image + reference-motion-video shape.
Lip sync
| Endpoint | Description |
|---|---|
| POST /v1/lipsync | a SEPARATE endpoint from /v1/videos — re-sync a face to a driving audio track, either animating a still (pass image_url + audio_url) or dubbing an existing clip's mouth to new speech (pass video_url + audio_url); async, returns a job id immediately; billed once at creation time from the driving audio's (or the longer of audio/video's) real duration |
| GET /v1/lipsync/models | live list of every valid model slug for POST /v1/lipsync; each row says whether it takes an image or a video input alongside audio_url; unbilled |
| GET /v1/lipsync/{id} | poll status — identical job-id scheme and response shape as GET /v1/videos/{id} |
Full guide: lip sync → Full parameters & example responses: Lip sync API reference →
Face swap
| Endpoint | Description |
|---|---|
| POST /v1/face-swap | a SEPARATE endpoint from /v1/videos — replace the face throughout an existing video (video_url) with a source face photo (face_image_url); requires source_face_consent: true; async, returns a job id immediately; billed reserve-then-settle from the provider's own completed-job invoice |
| GET /v1/face-swap/models | live list of every valid model slug for POST /v1/face-swap; unbilled |
| GET /v1/face-swap/{id} | poll status — identical job-id scheme and response shape as GET /v1/videos/{id} |
Full guide: face swap → Full parameters & example responses: Face swap API reference →
Talking avatars
| Endpoint | Description |
|---|---|
| POST /v1/avatars/videos | a talking avatar video: a catalog avatar_id or your own image_url (needs source_face_consent), plus script + voice_id or an audio_url. Async; optional webhook_url. Held then settled on the real video length |
| GET /v1/avatars/videos/{id} | poll status — same job object and cost_usd as GET /v1/videos/{id} |
| GET /v1/avatars | catalog avatars usable as avatar_id; filter ?type=, page with next_token; unbilled |
| GET /v1/avatars/voices | voices usable as voice_id; filter ?language=Arabic; unbilled |
| GET /v1/avatars/models | valid model slugs; unbilled |
3D generation
| Endpoint | Description |
|---|---|
| POST /v1/meshes | submit a text-to-3d (prompt), image-to-3d (image_url), or multi-image-to-3d (image_urls) job — async, returns a job id immediately; billed flat at creation time from the model + option choice |
| GET /v1/meshes/models | live list of every valid model slug for POST /v1/meshes, with the input shape each takes (text, image, multi-image); unbilled |
| GET /v1/meshes/{id} | poll status; the finished mesh (GLB + whichever of FBX/OBJ/USDZ/textures the model produces) is included once status is completed |
Full guide: 3D generation → Full parameters & example responses: 3D generation API reference →
Async Jobs
Submit a single request that's OK to wait 1 or 6 hours for a deeper discount — same body as
/v1/chat/completions, wrapped.
| Endpoint | Description |
|---|---|
| POST /v1/jobs | submit with completion_window: "1h" or "6h"; returns a job id, or push results to a webhook_url |
| GET /v1/jobs/{id} | poll status and read the result once completed |
Full guide: Async Jobs → Full parameters & example responses: Async Jobs API reference →
Batch
For bulk work on the full 24-hour window — the OpenAI-compatible Files + Batches shape, so any OpenAI Batch
SDK client works with a one-line base_url change.
| Endpoint | Description |
|---|---|
| POST /v1/files | upload a JSONL file of requests, purpose "batch" |
| GET /v1/files | list files |
| GET /v1/files/{id} | file metadata |
| GET /v1/files/{id}/content | download raw file content — input request lines, or the output/error JSONL once a batch completes |
| POST /v1/batches | create a batch from input_file_id, or an inline requests array for small jobs |
| GET /v1/batches | list batches |
| GET /v1/batches/{id} | status, progress counts, and output/error file ids once complete |
| POST /v1/batches/{id}/cancel | cancel a batch any time before it completes |
Full guide: Batch API → Full parameters & example responses: Batch API reference →
API key management
Create, cap and revoke API keys for your whole workspace, and read its spend by day, key, end user and app — from your own tooling. These routes take a management key (create one at Org admin → API Keys → Management Keys), not a regular API key, and can't call model endpoints.
| Endpoint | Description |
|---|---|
| GET /api/v1/keys | list keys, with current usage |
| POST /api/v1/keys | create a key with an optional daily / weekly / monthly spend limit |
| GET /api/v1/keys/{hash} | one key's limit and usage |
| PATCH /api/v1/keys/{hash} | rename, change the limit, or revoke |
| DELETE /api/v1/keys/{hash} | revoke a key |
| GET /api/v1/usage | daily spend by key, end user, app or model |
Full parameters & example responses: API key management reference →