Generate a video
POST /v2/video_generation
Request
| Field | Type | Required | Notes |
|---|---|---|---|
model | string | yes | MiniMax-H3, MiniMax-H3-Fast, MiniMax-H3-Economy |
content | array | yes | Exactly one text item, plus optional media |
resolution | string | yes | 768P only |
duration | integer | yes | 5–15 seconds |
ratio | string | no | adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16 |
callback_url | string | no | See callbacks |
Response: { "task_id": "424010985738629" }.
The three model names select a tier: different TPU topologies, so different latency, concurrency and price. The request shape is identical across them.
The three modes
Which mode runs is inferred from content. You do not pick it.
Text to video and audio
{
"model": "MiniMax-H3",
"content": [{ "type": "text", "text": "…" }],
"resolution": "768P",
"duration": 10,
"ratio": "16:9"
}
ratio is required here and cannot be adaptive — with no input image, there
is nothing to adapt to.
First or last frame
Supply one or two images to pin the ends of the clip.
{
"content": [
{ "type": "text", "text": "…" },
{
"type": "image_url",
"image_url": { "url": "https://example.com/first.png" },
"role": "first_frame"
}
],
"ratio": "adaptive"
}
role is first_frame or last_frame. A single image with no role is treated
as the first frame; a second unroled image is rejected rather than guessed at.
The image dictates the aspect ratio, so ratio is ignored.
Reference to video and audio
Up to nine images, three videos and three audio clips, as style, subject or voice references.
{
"content": [
{ "type": "text", "text": "…" },
{
"type": "video_url",
"video_url": { "url": "mm_file://424010985738629" },
"role": "reference_video"
},
{
"type": "audio_url",
"audio_url": { "url": "https://example.com/voice.mp3" },
"role": "reference_audio"
}
]
}
Keyframe roles and reference roles cannot be mixed in one request: they run on different checkpoints.
Reference mode needs a separately deployed worker pool. If this deployment is not running one, the request returns
503naming the reason rather than queueing forever.
Media inputs
Three URL forms work anywhere a url is accepted:
- a public
https://URL mm_file://{file_id}from the files API- a base64 data URI,
data:image/png;base64,…
Limits: images ≤ 30 MB, video ≤ 50 MB, audio ≤ 15 MB, whole request ≤ 64 MB.
Prefer mm_file:// over base64 — a data URI has to travel through every hop in
between.
Duration, and why you may get more than you asked for
The visual decoder works in clips of 17 frames with a 5-frame lead-in, so only
frame counts of the form 17n + 5 decode. The model additionally requires that
count to land between 120 and 360, and rounds up.
| You ask | Frames | You get |
|---|---|---|
| 5 s | 124 | 5.17 s |
| 8 s | 192 | 8.00 s |
| 10 s | 243 | 10.13 s |
| 15 s | 345 | 14.38 s |
You are billed for the duration you requested, so the overshoot is free. The one case that runs short is 15 s: 360 frames would round to 362, past the ceiling, so it clamps to 14.38 s.
Four seconds is not available. It is 96 frames, which rounds to 107 — below the
120-frame floor. The hosted MiniMax API accepts duration: 4; this deployment
returns a 400 explaining why instead of quietly giving you five seconds.
Query a task
GET /v2/query/video_generation/{task_id}
status is one of queued, running, succeeded, failed, cancelled.
content.url appears once the task succeeds. It is signed and expires in an
hour, and it is generated at query time — so a link that has expired is fixed
by querying again, not by asking support.
usage is the billing record: output_seconds is what you asked for,
input_seconds is measured reference media, input_image_count is reference
images.
Cancel
POST /v2/video_generation/{task_id}/cancel
Works while a task is queued or running, and refunds the entire hold.
Cancelling a finished task is a 400.
This endpoint is an extension: the hosted API documents a cancelled status
but nothing that produces it.