von 0G Foundation
MiniMax-H3 (Hailuo-03) text-to-video and image-to-video, billed per generated second. `seconds` must be 4-15, and outside that range it is silently clamped rather than rejected. `size` names a resolution TIER, not output dimensions: send one of the names listed under Resolution Tiers. OpenAI pixel dimensions (1280x720) are also accepted, but they set only the aspect ratio and only for text-to-video — on image-to-video the ratio follows your reference image, so pixel dimensions have no effect there, while a tier name still selects the tier. Prompt required, up to 7000 characters. Image-to-video takes one first-frame image via multipart `input_reference`. Async: POST /v1/videos, poll GET /v1/videos/{id} until completed, then GET /v1/videos/{id}/content for the MP4.
$0.195
pro generierter Sekunde
2K
Abrechnungsstufen – nicht die Größe, die Sie senden
Async-API — Die Videogenerierung verwendet einen asynchronen Ablauf: Reichen Sie einen Auftrag ein, fragen Sie ab, bis er abgeschlossen ist, und laden Sie die Datei dann von einem separaten Endpunkt herunter. Die Generierung dauert Minuten, fragen Sie also alle 3–5 Sekunden ab. Die folgenden Beispiele zeigen alle drei Schritte.
# 1. Submit the job. model, prompt and seconds are required; size is not.
# Omitting size is the recommended default — the model's own tier and aspect ratio apply. Each account may
# hold only a small number of unfinished jobs at once — 5 by default, set per deployment — and one over
# that returns 429 video_jobs_in_flight_limit.
#
# Some models clamp "seconds" INTO their supported range in BOTH directions rather than rejecting it,
# silently: below the minimum you get and pay for the minimum, above the maximum you get the maximum, and
# neither errors. That is the model's own behaviour, not something the router enforces, so check the model
# description for the range and for whether it clamps. You are billed for the clip actually produced, so
# where clamping happens a value outside the range costs something other than what you asked for. Not
# unlimited forgiveness: on a model whose price table is keyed on DURATION (variants carrying a
# duration_seconds dimension), a duration with no row is rejected up front with 400, listing the ones it
# does have. A model priced per second at a flat or resolution-only rate has a price for every duration, so
# that 400 cannot occur there.
#
# "size" names a resolution TIER, not output dimensions, and the two spellings are not equivalent. Pixel
# dimensions ("1280x720", OpenAI's spelling and what an SDK sends) select the ASPECT RATIO only, and only
# for text-to-video: on a 2K-only model they return a 2560x1440 clip billed at the 2K rate, not a 720p one.
# A tier name ("2K") addresses the tier directly — send only names that appear in
# pricing.variants[].dimensions.resolution, listed on this page under Resolution Tiers. On image-to-video
# the aspect ratio follows your reference image, so pixel dimensions have no effect there; a tier name
# still selects the tier.
curl "https://router-api.0g.ai/v1/videos" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-d '{
"model": "minimax-h3",
"prompt": "A cat surfing a wave at sunset",
"seconds": 6
}'
# Image-to-video is this same request with ONE more field — not a different flow, and not a different
# transport. Add "input_reference" to the body above; steps 2 and 3 are unchanged. It takes any of
# {"image_url": "https://…/first_frame.jpg"} for a reachable URL, {"image_url": "data:image/jpeg;base64,…"}
# for a local frame, or {"file_id": "…"}. An SDK sending a local file uses multipart instead, which the
# broker converts to that same data: URI — so the transport is a detail, the field is the interface.
# Prefer a URL for a large frame: base64 inflates the body by about a third, and the whole request must be
# 24 MB or less — over that it is 413 payload_too_large, tighter than the model vendor's own limit, so an
# image prepared against the vendor's docs can still be refused. One still frame only: last frame and
# reference image/video/audio are not exposed.
# Response: {"id": "v0_426354818031858", "status": "queued", "provider_address": "0x..."}
# 2. Poll until status is "completed". Generation takes minutes — 3-5s is a sane interval. The poll answers
# 200 and reports the job's own status, so a failure arrives as 200 + {"status":"failed"}, NOT as an error
# code. The SUBMIT response echoes what you sent; the POLL response reports what was actually rendered — so
# reconcile against the poll. Which fields carry that answer depends on the upstream:
# usage.output_video_duration when the provider reported a duration, size/seconds on some providers and not
# others. Read what is present rather than assuming a particular field.
curl "https://router-api.0g.ai/v1/videos/<VIDEO_ID>" \
-H "Authorization: Bearer <YOUR_API_KEY>"
# 3. Download the finished file. This is where 409 / 424 / 429 live: 409 = not ready yet, 429 = too many
# concurrent downloads (both retryable), 424 = the job failed and has no output (terminal).
curl "https://router-api.0g.ai/v1/videos/<VIDEO_ID>/content" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-o video.mp4
Anbieter-Routing
Steuern Sie, welcher Anbieter Ihre Anfrage bearbeitet, mit den X-0G-Provider-*-Anfrage-Headern.
curl "https://router-api.0g.ai/v1/videos" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-H "X-0G-Provider-Sort: latency" \
-H "X-0G-Provider-Allow-Fallbacks: true" \
-d '{
"model": "minimax-h3",
"prompt": "A cat surfing a wave at sunset",
"seconds": 6
}'