Video Generation
Serve the OpenAI Videos job API from your own instance — submit and poll, per-second billing, and which task dialects the gateway speaks.
The self-hosted gateway serves the OpenAI Videos job API beside the chat
and image endpoints: POST /v1/videos submits a generation job and
returns immediately with a job resource the caller polls at
GET /v1/videos/{id}; the finished clip downloads from
GET /v1/videos/{id}/content. Which models answer is your configuration:
a model must declare video output (output_modalities), and its
candidates bill per delivered second. GET /v1/models lists every
model's output_modalities, so clients can discover the video models an
instance serves.
Quick start
# Submit a job — the connection returns as soon as the upstream accepts it.
curl http://localhost:8080/v1/videos \
-H "Authorization: Bearer sk-yr-..." \
-H "Content-Type: application/json" \
-d '{"model":"wan2.7-t2v","prompt":"a lantern festival at night","seconds":4,"size":"720x1280"}'
# → {"id":"vid_...","object":"video","status":"queued",...}
# Poll until status is completed or failed.
curl http://localhost:8080/v1/videos/vid_... \
-H "Authorization: Bearer sk-yr-..."
# Download the finished clip.
curl http://localhost:8080/v1/videos/vid_.../content \
-H "Authorization: Bearer sk-yr-..." -o clip.mp4The official OpenAI SDK works unchanged — its videos.create posts
multipart, which the gateway parses alongside plain JSON, and
create_and_poll drives the poll loop for you.
The job resource
status is the four-value vocabulary the SDK's typing accepts —
queued, in_progress, completed, failed. A job the gateway
retired internally (the upstream window closed, or the provider's
address changed under it) renders as failed with an error.code of
task_expired or task_cancelled, so a strict client never meets a
word it cannot parse. On completion the resource carries
completed_at and an expires_at — the upstream result URL's own
window, after which /content no longer answers.
What the gateway reads
model (required), prompt, seconds (one of 4, 8, 12),
size (one of 720x1280, 1280x720, 1024x1792, 1792x1024), and
input_reference — a reference image as a URL, a base64 data URL, or an
attached file (multipart). Unknown fields are ignored, so newer SDKs do
not break older gateways. input_reference.file_id (the Files API) is
refused with a clear 400: this gateway has no file store.
Task dialects
Video upstreams are task-based, and the gateway speaks four of them natively:
-
DashScope (
dashscope.aliyuncs.com,dashscope-intl.aliyuncs.com, and Model Studio workspace domains): the wan families,wan2.7/wan3.0in one request shape andwan2.1–wan2.6in another. Model names outside those families are refused per candidate rather than guessed at. -
Ark (
*.volces.com): the Seedance family through its uniform content-generation task endpoint. No family gate — the same endpoint also accepts inference endpoint ids, so the provider test judges the mapping. Two account-side notes from the vendor docs: activating Seedance 2.0 and 2.0-fast requires an account balance of at least ¥200 (mini does not), and 2.0-fast does not serve 1080p — size a fast-tier candidate's price table accordingly, a 1080p ask against it is refused by the upstream itself. A provider key whose test model is a media model is verified through the media probes when the chat probe cannot serve the model there — the refusal shape a media-only account produces (the trigger deliberately includes any upstream error on the chat side, so a genuine chat outage may cost the account one extra probe round). An account that opened only video (or only image) models can still have its key verified against the model it actually serves. -
Kling (
*.klingai.com): the new-design API — the model version rides in the path — authenticated with the single API key the console's API Key page issues (it ridesBearerverbatim and is shown only once); the old/v1endpoint family's AK/SK + JWT path is not a channel this gateway speaks. The model whitelist iskling-3.0andkling-3.0-turbo(text-to-video and first-frame image-to-video; the dialect's 4/8/12 seconds pass through, the upstream itself accepts 3–15). Account-side notes from the vendor docs: billing is per second in credits (1 credit ≈ ¥1; 3.0-Turbo is ¥0.8/s at 720p and ¥1.0/s at 1080p), so size the resolution-tier table accordingly; result files are cleaned by the upstream after 30 days (far longer than the other dialects' 24 hours, still worth re-hosting promptly); concurrency is counted per account × model version × resource pack — an account with no pack may have zero concurrency, and submits then answer1303; the upstream has no cancel endpoint. Key verification goes through the media probe (a 3-second shortest-task submit plus one query) — it generates and bills for real. Two upstream-side errors worth knowing by name: an exhausted credit or resource-pack balance answers1102 "Account balance not enough"— the key's media probe fails verification and routing answers 503 until the account is topped up; concurrency past the resource pack's ceiling answers1303, which clears when in-flight jobs finish or the pack is upgraded. Vendor docs: klingai.com/document-api (the authentication and video endpoint pages). -
MiniMax (
api.minimax.cn): the V2 task API — one submit route with the model in the body, the task id in the query path. The model whitelist isMiniMax-H3andMiniMax-H3-Max(text-to-video and first-frame image-to-video). The two models map the door sizes differently: H3 rides the large sizes at its 2K top, H3-Max has no 2K and stays at 768P — and its clips run 5–15 seconds, so a 4-second ask is refused for that model with that reason (never silently rewritten). Refusals arrive as real HTTP statuses in an OpenAI-shaped body; the caller sees the status and the vendor's wording lives on the audit row. Account-side notes from the vendor docs: video generation bills the pay-as-you-go balance — Token Plan subscriptions, credit packs, and the Hailuo video resource packs do not cover the H3 models, so top up the balance for both testing and production; H3-Max input images are currently not billed; tasks are queryable for 7 days only (beyond that a pending job expires unbilled), and the finished-clip link is time-limited — download or re-host promptly, the gateway prices and settles from the seconds the task reports. Key verification goes through the media probes when the chat probe cannot serve the model — the same host serves the chat dialect beside the V2 task one. Vendor docs: platform.minimaxi.com/docs (the video-generation V2 pages).
Other bases answer with a per-candidate refusal. A submitted task is
never re-submitted to another candidate: a job the upstream later fails
is the caller's failed with the upstream's own error, not a silent
retry.
Billing
Per second, from the candidate's resolution-tiered price table: the submit prices the job at its stated seconds against the tier its size maps to, and that submit-time price is the snapshot every settlement charges — editing the table later does not reprice a job already in flight. Settlement happens once, when completion is first observed, on the seconds the upstream actually reports. Failed, cancelled, and expired jobs bill nothing.
The submit also reserves: your key's budget counts every unfinished job's priced bound, so parallel submits cannot spend past the limit through the gap between jobs finishing and their charges landing. An over-budget submit is refused with 429 and the full arithmetic.
Limitations
- Result URLs belong to the upstream: they expire on its schedule
(typically 24 hours),
/contentproxies rather than re-hosts, and the gateway stores no video files. - Job rows are kept forever as billing evidence; the upstream's own
task window is shorter, after which polls read
task_expired. - There is no job cancellation surface: the wire's dialect has none to expose.
Image Generation
Serve the OpenAI Images API from your own instance — generations and edits, streaming, per-image billing, and what the gateway forwards.
Speech Generation
Serve the OpenAI Speech API from your own instance — one endpoint, three dialects, per-character billing in each provider's own counting rule.