Docs
Get an API key
API reference›Videos

Create Video

POST /v1/videos Models: Video View .md

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. At 2K a render takes about 3 times as long: a 15 s text job takes about 140 s. 4K adds SeedVR2's upscale of that 2K render, about 18 s per second of video (a 15 s text job takes about 7 minutes), plus any wait for a free upscaler, which progress does not count. 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 1.5 times the seconds; max (or high) runs 40 steps and bills 3 times; ultra runs 50 steps and bills 5 times. For finer control send num_inference_steps from 10 to 50 instead (OpenRouter's SDKs: provider.options.stealth.quality 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, max_per_second and ultra_per_second are the tiers' prices, 2K_per_second and 4K_per_second the 2K and 4K prices), only when the job completes. standard bills 1.5 times the seconds, max 3 times and ultra 5 times; resolution: 2K and 4K (Turbo only) 3 times: 4K bills as the 2K it upscales. A raw num_inference_steps bills the tier whose step range holds it: 10 to 20 as standard, 21 to 40 as max, 41 to 50 as ultra (quality_tiers[].step_range in GET /v1/videos/models). Billed seconds are rounded up to a whole second: a 5 s job at standard bills 8 s. usage.billed_seconds shows the result. Failed and cancelled jobs are not billed.

Guides: Async jobs, Webhooks, Render a video with webhooks, Write prompts for MiniMax-H3

A 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_parameter, 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 8000 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; duration wins when both are sent.

  • resolution string

    minimax-h3: 2K renders the 768p preset and enlarges it 2x (16:9 is 2688x1536). It bills 3 times the seconds times the quality tier, takes about 3 times as long, and runs at every tier: quality standard, max or ultra, or base num_inference_steps, renders the 768p preset on the base weights before the same upscale. 4K is the 2K render enlarged 1.5x by SeedVR2 after the engine (16:9 is 4032x2304, the soundtrack kept): it bills as 2K (the upscale is free), runs at Turbo only (any other tier at 4K is a 400), and takes about 18 s more per second of video, plus any wait for the upscaler; the job's output.upscale says it was applied.

    default 768p768p2K4K
  • aspect_ratio string
    default 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. The second six are 2K and the last six 4K (see resolution).

    1344x768768x13441024x768768x1024768x7681536x6722688x15361536x26882048x15361536x20481536x15363072x13444032x23042304x40323072x23042304x30722304x23044608x2016
  • frame_images array of objects
    at most 2 items
    3 fields
    • type string required
      image_url
    • image_url object required
      1 field
      • url string required

        An https URL or a base64 data URI.

    • frame_type string required
      first_framelast_frame
  • input_references array of objects

    Reference media for the subject, style or sound. Ignored when frame_images is sent.

    5 fields
    • type string required
      image_urlvideo_urlaudio_url
    • image_url object
      1 field
      • url string required

        An https URL or a base64 data URI.

    • video_url object
      1 field
      • url string required

        An https URL or a base64 data URI.

    • audio_url object
      1 field
      • url string required

        An https URL or a base64 data URI.

    • role string

      driving and control are reserved for models that support them.

      default referencereference
  • input_reference string or object

    OpenAI/Sora's first frame, as an https URL (or base64 data URI) string or as {image_url}. Ignored when frame_images is sent. Any other type is a 400.

    One of 2
    • string
    • object
      • image_url string
  • generate_audio boolean

    Strictly true or false (in multipart/form-data the text true or false); 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 the quality tier whose step range holds the count: 10 to 20 as standard (1.5x), 21 to 40 as max (3x), 41 to 50 as ultra (5x; see Billing). Sending the Turbo count itself changes nothing. Prefer quality. Also accepted under provider.options (see provider).

    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 1.5x; max (high) is 40 base steps at 3x; ultra is 50 base steps at 5x. The job stores the tier's own name. Sending num_inference_steps too is a 400 unless it is the tier's count. Also accepted under provider.options (see provider).

    turbostandardmaxultraautolowmediumhigh
  • start_time_seconds number

    minimax-h3: where to start reading each reference video in input_references, in seconds. Also accepted under provider.options (see provider).

    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. options carries the model's own settings (quality, num_inference_steps, start_time_seconds for minimax-h3; GET /v1/videos/models lists each model's allowed_passthrough_parameters) for clients that cannot add top-level fields. From OpenRouter's SDKs use options.stealth: they keep only the slugs on their closed list and drop any other, vultr included, 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.

Fields as multipart/form-data
  • model string required
  • prompt string required
  • seconds string
  • size string
  • input_reference string (binary)

    The first frame.

  • generate_audio string
    truefalse
  • callback_url string

Accepted. The job, pending, with its polling_url and queue_position.

application/json · video-job-payload

18 fields
  • id string required
  • object string required
    video
  • model string required
  • status string required

    OpenAI's SDKs (requests with X-Stainless-Lang) see queued for pending, and cancelled and expired as failed with that reason as error.code; everyone else sees the states below.

    • pending: queued; see queue_position.
    • in_progress: rendering; see progress.
    • completed: the video is ready at unsigned_urls until expires_at. The only billed status.
    • failed: see error. Not billed.
    • cancelled: cancelled with DELETE /v1/videos/{id}. Not billed.
    • expired: a completed job past its 7-day retention; the video is deleted.
    pendingqueuedin_progresscompletedfailedcancelledexpired
  • progress integer required

    Estimated percent complete while rendering.

  • created_at integer required
  • completed_at integer
  • expires_at integer

    When the video is deleted.

  • polling_url string required
  • seconds string

    The requested duration.

  • size string
  • queue_position integer

    Jobs ahead of this one for the same model, while pending.

  • unsigned_urls array of strings

    Where to download each output (send your API key).

  • output object

    What was rendered.

    8 fields
    • duration number
    • fps number
    • width integer
    • height integer
    • has_audio boolean
    • count integer
    • trimmed_seconds number

      Seconds cut from the start of the clip because it opened on one of the input reference images before the requested scene (minimax-h3 reference-to-video). Present only when something was cut; duration is the length delivered.

    • upscale object

      Present only for a size SeedVR2 enlarged after the engine (minimax-h3's 4K), which is never delivered without it.

      2 fields
      • applied boolean
      • model string
  • warnings array of objects

    What the request sent that was not read. Always present; an empty list says nothing was ignored.

    3 fields
    • code string

      unknown_parameter: not a video request field, so it was not read. Codes are open: ignore one you do not know.

    • field string
    • message string
  • usage object
    6 fields
    • cost number

      USD.

    • output_seconds integer

      Seconds of video requested.

    • billed_seconds integer

      Seconds billed at the model's price; more than output_seconds for the standard (1.5x), max (3x) and ultra (5x) quality tiers, for base num_inference_steps (the tier whose step range holds the count) and at 2K and 4K (3x), rounded up to a whole second.

    • input_image_count integer
    • input_video_seconds number
    • input_audio_seconds number
  • error string or object

    Why a failed job failed. A string beside error_code; for OpenAI's SDKs an object with code and message.

    One of 2
    • string
    • object
      • code string

        The same values as error_code, and cancelled or expired for a job in that state.

        invalid_requestpayload_too_largetimeoutprovider_errorserver_errorcancelledexpired
      • message string
  • error_code string
    • invalid_request: an input could not be used, for example a media URL that could not be fetched or a file of the wrong type. Fix the request before sending it again.
    • payload_too_large: a media input was over its size limit.
    • timeout: the render took too long.
    • provider_error: the render failed or was interrupted on our side. Sending the same request again is safe.
    • server_error: the job could not run, for example because its model or API key was removed.
    invalid_requestpayload_too_largetimeoutprovider_errorserver_error
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"
  }'
Response · 202
{
    "id": "video_3f2a9c1e7b4d5a6c8e0f1a2b",
    "object": "video",
    "model": "string",
    "status": "pending",
    "progress": 0,
    "created_at": 1790000000,
    "polling_url": "string"
}