Create Video
Starts a video render and answers 202 at once with the job; poll its polling_url, or pass callback_url to be notified. The request follows OpenRouter's video API, so the OpenRouter SDKs work by changing the base URL and key. OpenAI/Sora field names are accepted too: seconds for duration, size, and input_reference (an uploaded file in multipart/form-data, an https URL string, or {image_url}) for the first frame. GET /v1/videos/models lists the models with what each accepts.
Modes (minimax-h3): text only; frame_images with a first_frame, a last_frame or both; or input_references (up to 9 images, 3 videos and 3 audio clips, 12 in all). When both frame_images and input_references are sent, frame_images is used.
Media: an https URL or a base64 data URI. Images JPG, PNG, WEBP, HEIC or HEIF up to 30 MB; videos MP4 or MOV up to 50 MB, 2-15 s; audio WAV or MP3 up to 15 MB, 2-15 s.
Sizes (minimax-h3): 4 to 15 seconds at 24 fps, with stereo AAC audio. Send aspect_ratio or size:
aspect_ratio |
size |
|---|---|
16:9 (default) |
1344x768 |
9:16 |
768x1344 |
4:3 |
1024x768 |
3:4 |
768x1024 |
1:1 |
768x768 |
21:9 |
1536x672 |
Output: duration snaps to the model's frame grid, so a 4 s request is about 4.4 s; read output.duration. Videos have a generated soundtrack unless generate_audio is false.
Prompts are used as written. MiniMax's and fal's APIs rewrite prompts by default, so the same prompt can give a different video here.
Expected wait: while a job is pending, queue_position counts the jobs ahead of it for the same model. Once it starts, a minimax-h3 render takes about 3 seconds per second of video for text and frame jobs, and about 5 seconds per second with input_references: a 6 s text job is ready in about 20 s. progress is estimated from these times.
Quality (minimax-h3): quality picks a tier, the same in every mode. turbo (or auto, low; the default) uses H3's Turbo LoRA: 4 denoising steps, or 8 with input_references. standard (or medium) runs the full base model at 20 steps and bills 3 times the seconds; max (or high) runs 40 steps and bills 5 times. For finer control send num_inference_steps from 10 to 50 instead (OpenRouter's SDKs: provider. or .num_inference_steps); more steps take longer and cost more. Sending a tier and a different step count is a 400.
Billing: per second of requested duration at the model's price (pricing_skus in GET /v1/videos/models; standard_per_second and max_per_second are the tiers' prices), only when the job completes. standard bills 3 times the seconds and max 5 times. A raw num_inference_steps bills steps / 6 times the seconds, never more than the next tier up (19 steps bill as standard), rounded up to a whole second: a 10 s job at 25 steps bills 42 s. usage.billed_seconds shows the result. Failed and cancelled jobs are not billed.
Body
application/jsonA control another video model takes that this model does not have (guidance_scale, negative_prompt; minimax-h3 is CFG-distilled and has neither) is a 400 with metadata.error_type unsupported_, and so is lora or loras. Any other field the model does not read is accepted and listed in the job's warnings; the video is made without it.
-
model string required
-
prompt string required
Must be a string (a list or number is a 400).
at most 7000 characters -
duration integer
Seconds of video. minimax-h3 takes 4-15; default 6. A whole number sent as text (
"8") is accepted. -
seconds integer
OpenAI/Sora's name for
duration;durationwins when both are sent. -
resolution string
-
aspect_ratio stringdefault 16:916:99:164:33:41:121:9
-
size string
Width x height; an alternative to
aspect_ratio, and must agree with it when both are sent.1344x768768x13441024x768768x1024768x7681536x672 -
frame_images array of objectsat most 2 items
-
input_references array of objects
Reference media for the subject, style or sound. Ignored when
frame_imagesis sent. -
input_reference string or object
OpenAI/Sora's first frame, as an https URL (or base64 data URI) string or as
{image_url}. Ignored whenframe_imagesis sent. Any other type is a 400. -
generate_audio boolean
Strictly
trueorfalse(inmultipart/form-datathe texttrueorfalse); anything else is a 400.default true -
seed integer
-
num_inference_steps integer
minimax-h3: the number of denoising steps. Omit it for the Turbo LoRA (4 steps, or 8 with
input_references); 10 to 50 runs the full base model, which takes longer and bills steps / 6 times the seconds, capped at the nextqualitytier up (see Billing). Sending the Turbo count itself changes nothing. Preferquality. Also accepted underprovider.options(seeprovider).range 4–50 -
quality string
minimax-h3: the quality tier, the same in every mode.
turbo(auto,low; the default) is the Turbo LoRA at 1x the price;standard(medium) is 20 base steps at 3x;max(high) is 40 base steps at 5x. The job stores the tier's own name. Sendingnum_inference_stepstoo is a 400 unless it is the tier's count. Also accepted underprovider.options(seeprovider).turbostandardmaxautolowmediumhigh -
start_time_seconds number
minimax-h3: where to start reading each reference video in
input_references, in seconds. Also accepted underprovider.options(seeprovider).at least 0 -
callback_url string
An https URL notified on completion, failure, cancellation and expiry. See
GET /v1/webhooks/secret. -
provider object
OpenRouter's provider preferences. The routing fields (
order,only,ignore,sort,allow_fallbacks, ...) are accepted and ignored.optionscarries the model's own settings (quality,num_inference_steps,start_time_secondsfor minimax-h3;GET /v1/videos/modelslists each model'sallowed_) for clients that cannot add top-level fields. From OpenRouter's SDKs usepassthrough_ parameters options.stealth: they keep only the slugs on their closed list and drop any other,vultrincluded, without an error. The first form present wins, the top level before any option; a key the model does not declare is a 400 naming its path.
Body
multipart/form-dataResponses
Accepted. The job, pending, with its polling_url and queue_position.
application/json · video-job-payload
A field the model does not support or a malformed input. The message names the field. Fields are typed, not coerced; prompt must be a string, generate_audio a boolean (true or false), input_reference a URL string or an object - and a whole number may be sent as text ("20").
application/json · error-payload
The API key is missing, unknown or not active. Send it as Authorization: Bearer <key>.
application/json · error-payload
Unknown video model
application/json · error-payload
The model has no valid capability spec at the moment and is not served.
application/json · error-payload
A media input is over its size limit
application/json · error-payload
curl https://api.vultrinference.com/v1/videos \
-H "Authorization: Bearer $VULTR_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"prompt": "A red fox trots through fresh snow at dawn, breath steaming.",
"duration": 6,
"aspect_ratio": "16:9",
"callback_url": "https://example.com/hooks/video"
}'import os
import requests
response = requests.post(
"https://api.vultrinference.com/v1/videos",
headers={"Authorization": f"Bearer {os.environ['VULTR_INFERENCE_API_KEY']}"},
json={
"model": "minimax-h3",
"prompt": "A red fox trots through fresh snow at dawn, breath steaming.",
"duration": 6,
"aspect_ratio": "16:9",
"callback_url": "https://example.com/hooks/video",
},
)
print(response.json())const response = await fetch("https://api.vultrinference.com/v1/videos", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VULTR_INFERENCE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "minimax-h3",
"prompt": "A red fox trots through fresh snow at dawn, breath steaming.",
"duration": 6,
"aspect_ratio": "16:9",
"callback_url": "https://example.com/hooks/video"
}),
});
console.log(await response.json());{
"id": "video_3f2a9c1e7b4d5a6c8e0f1a2b",
"object": "video",
"model": "string",
"status": "pending",
"progress": 0,
"created_at": 1790000000,
"polling_url": "string"
}