Skip to content

MiniMax Hailuo

Hailuo is MiniMax’s video generation family. One channel serves two API generations: MiniMax-H3 and MiniMax-H3-Max use MiniMax’s /v2 API with a content array and settle per second, while the MiniMax-Hailuo-2.3 family uses the older /v1 API with a per-task price (covered at the end of this page).

Tasks are submitted, polled and downloaded through the shared endpoints described in Create a task and Get a task. This page covers what this vendor reads, how the request is built, and how it is billed.

Model IDResolutionsDuration (integer seconds)DefaultsPrompt expansion
MiniMax-H3768P, 2K4–15768P, 5 sNo
MiniMax-H3-Max480P, 768P5–15768P, 5 sYes
  • Use the model ID exactly as written here — IDs are case-sensitive. Your account can use only the models routed to it, and price is per account; GET /v1/models is the authoritative list for your key.
  • MiniMax-H3-Max is the only model that accepts extra. Sending extra to MiniMax-H3 returns 400.
  • Text-to-video, first-frame, first-and-last-frame, and reference image / video / audio are all supported by both models.
FieldTypeRequiredDefaultDescription
modelstringYes—Model ID from GET /v1/models
promptstringYes—Text prompt; blank after trimming is rejected. Up to 7000 characters
resolutionstringNo768PCase-insensitive; must be one of the model’s resolutions
durationintegerNo5Integer seconds inside the model’s range
secondsstringNo—String form of the duration; read only when duration is missing or 0
ratiostringNosee belowAspect ratio
imagesstring[]No—1 image = first frame; 2 images = first frame then last frame. At most 2
imagestringNo—Single image; used only when images is empty
metadataobjectNo—MiniMax parameters, see the next section

Precedence rules:

  • metadata.resolution, metadata.duration and metadata.ratio override the top-level fields of the same name.
  • seconds is only read when the top-level duration is absent or 0, and metadata.duration overrides both.
  • metadata.duration is parsed as a number, so 5.5 fails with invalid duration. Unlike the top-level duration, 0 is not “unset” there — it is out of range. Omit the key to keep the default.
  • size is not supported. A top-level size or metadata.size returns MiniMax-H3 请使用 resolution(480P/768P/2K),不支持 size; use resolution instead.
  • Apart from size, top-level fields this vendor does not read (for example generate_audio or input_reference) are ignored rather than rejected.
FieldTypeDescription
contentarrayInput material, see Content items. Cannot be combined with top-level images / image
resolutionstringOverrides the top-level resolution
durationnumberOverrides the top-level duration and seconds; must be an integer in range
ratiostringOverrides the top-level ratio
aigc_watermarkboolean or stringtrue / false. A string "true" or "false" is also accepted, which is what multipart forms send. Omitted = upstream decides
extra.prompt_expansion_modestringdisabled, balanced or quality. MiniMax-H3-Max only
size—Rejected with 400

metadata is decoded into a typed structure: a wrong JSON type for one of the keys above (for example "duration": "abc", or content as an object) returns 400 with invalid metadata: ... and nothing is charged. Keys that are not in the table — seed, callback_url and so on — are ignored and never reach MiniMax; no callback is sent, so poll for the result.

Accepted values: adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16. The value is case-insensitive.

Request shapeRatio omittedRules
Text only (no frames, no references)16:9adaptive is rejected with text-to-video does not support ratio adaptive
First frame, or first and last frameadaptiveForced to adaptive; any value you send is ignored, and is not validated
Reference mediaadaptiveAny of the seven values

metadata.content is an ordered array. Each item has a type, a payload field matching that type, and an optional role:

typePayloadAllowed roleLimit
texttextnone1, and must equal prompt
image_urlimage_url.urlfirst_frame1
image_urlimage_url.urllast_frame1, and requires first_frame
image_urlimage_url.urlreference_image9
image_urlimage_url.urlnoneonly as the single media item
video_urlvideo_url.urlreference_video (required)3
audio_urlaudio_url.urlreference_audio (required)3
{ "type": "image_url", "role": "reference_image", "image_url": { "url": "https://..." } }
{ "type": "video_url", "role": "reference_video", "video_url": { "url": "https://..." } }
{ "type": "audio_url", "role": "reference_audio", "audio_url": { "url": "https://..." } }

Rules enforced before the request is sent:

  • At most 12 media items per request, and at most 9 reference images, 3 reference videos and 3 reference audios.
  • First / last frame images and reference media cannot be mixed. reference_image, reference_video and reference_audio combine freely.
  • An image_url item without a role is allowed only when it is the only media item; it is then treated as first_frame.
  • If content has no text item, RouteAPI prepends one carrying the top-level prompt. If it has one, there can be only one, and its text must equal the trimmed prompt; otherwise the request fails with prompt 与 metadata.content 中的 text 冲突.
  • content and top-level images / image are mutually exclusive.
  • Only the field matching the item type is forwarded; extra keys on an item are dropped.
  • Media URLs — including top-level images and image — must be http://, https:// or data: URIs (for example data:image/png;base64,...) and must be downloadable without authentication. MiniMax file IDs (mm_file://) are not supported. URLs that MiniMax quotes back in a rejection are replaced with [url omitted], so signed asset links never appear in error messages.
  • Per-asset format, dimension, length and size limits are MiniMax’s own; RouteAPI does not check them. A bad asset is either rejected at submit (400, nothing charged) or rejected during generation (the task becomes FAILURE and the reservation is refunded).
Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "A paper boat drifting down a rain-soaked street, cinematic lighting",
"resolution": "768P",
"ratio": "16:9",
"duration": 5
}'
Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "The camera slowly pushes in as the subject looks up and smiles",
"images": ["https://cdn.example.com/first.jpg"],
"resolution": "768P",
"duration": 5
}'

Two entries in images become first_frame and last_frame. ratio is forced to adaptive.

Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "The scene transitions from morning to sunset while the camera pans smoothly",
"images": [
"https://cdn.example.com/first.jpg",
"https://cdn.example.com/last.jpg"
],
"resolution": "768P",
"duration": 5
}'

Use metadata.content when you need more than two images or any reference video / audio. Reference videos are billed, so keep them between 2 and 15 seconds — see Billing.

Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "The character in the image dances to the rhythm of the reference audio, copying the motion of the reference video",
"resolution": "768P",
"ratio": "9:16",
"duration": 8,
"metadata": {
"content": [
{ "type": "image_url", "role": "reference_image", "image_url": { "url": "https://cdn.example.com/character.jpg" } },
{ "type": "video_url", "role": "reference_video", "video_url": { "url": "https://cdn.example.com/motion.mp4" } },
{ "type": "audio_url", "role": "reference_audio", "audio_url": { "url": "https://cdn.example.com/music.mp3" } }
]
}
}'
Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3-Max",
"prompt": "A rainy city street at night, neon signs reflected in puddles",
"resolution": "480P",
"duration": 6,
"metadata": {
"aigc_watermark": false,
"extra": { "prompt_expansion_mode": "quality" }
}
}'
MiniMax task.statusdata.statusdata.progress
queuedQUEUED20%
runningIN_PROGRESS50%
succeeded with content.urlSUCCESS100%
succeeded without content.urlFAILURE100%
failed, cancelledFAILURE100%
any other valueIN_PROGRESS30%

A succeeded task with no video URL is failed with fail_reason upstream succeeded without video url and refunded. A failed or cancelled task reports MiniMax’s task.error.message (every URL removed and replaced with [url omitted]); when MiniMax sends no message the reason is task failed or task cancelled.

An error envelope ({"type":"error","error":{...}}) makes that poll cycle fail and the task is queried again next time. A body with no task object at all falls back to the older /v1 response shape, which is empty, so the task simply stays IN_PROGRESS. A task that never reaches a terminal state is failed by the platform timeout — 24 hours by default — with fail_reason 任务超时(1440分钟), and the reservation is refunded.

GET /v1/video/generations/{task_id} returns the RouteAPI task row; Get a task documents every field. For this vendor the useful ones are:

FieldDescription
data.status / data.progressTask state and progress, from the table above
data.result_urlVideo URL once the task succeeded
data.fail_reasonFailure reason, empty otherwise
data.quotaQuota charged for the task
data.properties.inputSnapshot of the request RouteAPI sent upstream, with media URLs replaced by [omitted, N bytes]; useful when disputing a charge
data.dataThe latest MiniMax payload
{
"code": "success",
"message": "",
"data": {
"task_id": "task_FQvcRkHE9wjSWwyISDcrWCKoqCPNdkCx",
"platform": "35",
"group": "default",
"action": "generate",
"status": "SUCCESS",
"progress": "100%",
"fail_reason": "",
"result_url": "https://cdn.minimax.example/video/424010985738629.mp4?Expires=...",
"submit_time": 1792412645,
"start_time": 1792412650,
"finish_time": 1792412780,
"data": {
"task": {
"id": "424010985738629",
"status": "succeeded",
"content": { "url": "https://cdn.minimax.example/video/424010985738629.mp4?Expires=..." },
"resolution": "768P",
"usage": {
"output_seconds": 5,
"input_seconds": 0,
"input_image_count": 1
}
}
}
}
}

Inner fields worth reading:

FieldDescription
data.data.task.idMiniMax task ID, different from the RouteAPI task_id
data.data.task.statusqueued, running, succeeded, failed or cancelled
data.data.task.content.urlVideo URL on success; this is what result_url holds
data.data.task.resolutionResolution MiniMax reports. Billing uses the requested one, not this
data.data.task.usage.output_secondsLength of the produced video, used for settlement
data.data.task.usage.input_secondsLength of the reference video, used for settlement
data.data.task.usage.input_image_countImage count reported by MiniMax; settlement uses the submitted count instead
data.data.task.error.code / .messageFailure detail when MiniMax reports one

Before the first successful poll, data.data is the raw submit response ({"task_id": "..."}) and has no task field. task.usage appears when MiniMax returns it, which is normally on success. Always branch on the outer data.status.

data.result_url already points at MiniMax’s CDN. That link expires on MiniMax’s schedule, so download it as soon as the task reports SUCCESS.

  • Direct CDN link: fetch it without an Authorization header; some storage rejects extra auth headers.
  • https://api.routeapi.ai/v1/videos/{task_id}/content: streams the same stored URL through RouteAPI and needs Authorization: Bearer $ROUTEAPI_KEY. It re-fetches the stored link, so it does not extend the expiry. Use it when your client must not see the upstream host, or when the CDN refuses direct access. It answers 404 Task not found for an unknown task, and 400 Task is not completed yet, current status: ... until the task succeeds.
Terminal window
# direct CDN link
curl -L -o out.mp4 "$RESULT_URL"
# RouteAPI proxy
curl -L -o out.mp4 -H "Authorization: Bearer $ROUTEAPI_KEY" \
"https://api.routeapi.ai/v1/videos/$TASK_ID/content"

Per-second billing applies when the model has a fixed price configured for your account (the console model detail page shows it). If the model is priced only by model ratio, the normal per-task charge applies and there is no completion-time settlement. With per-second billing, a charge has three components:

ComponentUnit priceCounted at submit (reservation)Counted at settlement
Output videoper second, for the requested resolutionthe requested durationmin(usage.output_seconds, duration)
Reference video inputper second, for the requested resolution15 s whenever content contains a reference_videousage.input_seconds, valid only in the 2–15 s range
Imagesper image beyond the free allowanceevery image item in the built content, frames includedthe same count from the submit snapshot

Prices and the free-image allowance are configured per account; the built-in defaults allow 5 free images on MiniMax-H3 and 2 on MiniMax-H3-Max, but the console is authoritative. No prices are quoted on this page.

TimingOutput secondsReference-video seconds
Reserved at submitthe requested duration15 s if the request has a reference video
Settled on successusage.output_seconds, capped at the requested durationusage.input_seconds when it is between 2 and 15 s

Rules:

  • Settlement only ever refunds: the final charge is the smaller of the recomputed amount and the reservation.
  • Settlement uses the unit prices frozen at submit time. A price change while a task is running does not affect it.
  • Without a reference video there is no input-seconds component at all, and usage.input_seconds is ignored.
  • Reference audio is free, and the image component does not change at settlement.
  • Because a request with a reference video reserves 15 s of input, the balance must cover that worst case even when the video is shorter.
  • If usage is missing, output_seconds is 0 or above 15, or (with a reference video) input_seconds is missing or outside 2–15, RouteAPI keeps the whole reservation and refunds nothing. Keep reference videos between 2 and 15 seconds to avoid that.
  • A failed or timed-out task refunds the whole reservation; a request rejected with 400 is never charged.
  • The submit response’s X-New-Api-Other-Ratios header carries the multiplier applied to the model price as h3_units (a 5-second 768P task is {"h3_units": 5}) when per-second billing applies. It is {} for the 2.3 family, and for an H3 model that is not priced with a fixed task price.

Hypothetical prices, for arithmetic only: MiniMax-H3 at 768P costs $0.10 per output second, $0.10 per reference-video second, and $0.04 per image beyond 5 free images. A 10-second request with two reference images and one reference video:

  • Reservation: 10 × 0.10 (output) + 15 × 0.10 (reference video, capped) + max(0, 2 − 5) × 0.04 (images) = $2.50.
  • MiniMax returns output_seconds: 8 and input_seconds: 6: 8 × 0.10 + 6 × 0.10 + 0 = $1.40.
  • The difference, $1.10, is returned to the balance.

Submission is validated before anything is reserved, so a 400 costs nothing. MiniMax business rejections arrive inside an HTTP 200 response and are mapped like this:

MiniMax base_resp.status_codeMeaningHTTP to youcode
1026Content / safety rejection4001026
2013Parameter error4002013
1002Rate limited4291002
1004, 2049Upstream key / auth failure401, normally returned as 5031004 / 2049, or get_channel_failed
1008Upstream balance exhausted503get_channel_failed
any other codeUnknown business error502the numeric code
— (unparsable body, or a type: "error" envelope)Malformed submit response502invalid_response
— (empty task_id)No upstream task ID502upstream_task_id_missing

Upstream account failures are never shown verbatim. The adaptor maps 1008 to 402 and the auth codes 1004 / 2049 to 401; RouteAPI then classifies the failure as a channel fault and answers 503 get_channel_failed with a generic “upstream service is temporarily unavailable” message, after trying another channel if one is available. The 402 from 1008 is surfaced as 503 for the same reason. MiniMax’s status_msg in these cases never reaches you. A 429 keeps its status but the message is replaced with a generic saturation notice. A 400 carries MiniMax’s own text prefixed with hailuo api error: .

If MiniMax answers with a non-200 HTTP status, the body is not parsed: you get code fail_to_fetch_task with that status. Querying an unknown or foreign task_id returns 400 with code task_not_exist.

Errors raised before the request reaches MiniMax follow the shared rules in Common Errors: 401 for a missing or invalid API key, 403 insufficient_user_quota when the balance cannot cover the reservation (including the 15-second reference-video worst case), and 403 with This token has no access to model ... when the key is not allowed to use the model.

Common 400 messages (code invalid_request unless noted):

messageCause
prompt is requiredprompt is missing or blank
seconds must be between 1 and 3600 (code invalid_seconds)Top-level duration is negative or above 3600
invalid seconds: abcseconds is not an integer string
<model> 请使用 resolution(480P/768P/2K),不支持 sizesize was sent at the top level or in metadata; the message names your model and always lists 480P/768P/2K
invalid resolution: 1080P, MiniMax-H3 supports 768P, 2KResolution not supported by that model
invalid duration: 3, MiniMax-H3 supports integer 4-15Duration below the model minimum, above 15, or not an integer
invalid ratio: 2:1, supports adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16Ratio not in the list
text-to-video does not support ratio adaptiveadaptive on a request with no frames and no references
at most 2 top-level images (first_frame, last_frame), got 3; use metadata.content for reference mediaMore than 2 entries in images
images must not contain empty valuesBlank entry in images
metadata.content cannot be combined with top-level imagesBoth were sent
metadata.content must be a non-empty arraycontent is []
prompt 与 metadata.content 中的 text 冲突The text item differs from prompt
metadata.content accepts at most one text itemMore than one text item
text exceeds 7000 charactersPrompt over 7000 characters
invalid content type "foo"Unknown type
invalid role "foo" for image_urlUnknown image role
image_url without role is only allowed as the single input imageUntagged image mixed with other media
last_frame requires first_frameOnly a last frame was sent
at most one first_frame and one last_frameDuplicate frame roles
first/last frame images cannot be combined with reference mediaFrames mixed with reference media
at most 9 reference images / at most 3 reference videos / at most 3 reference audios / at most 12 media itemsA per-type or total media limit was exceeded
video_url requires role reference_video / audio_url requires role reference_audioWrong or missing role for that item type
image_url.url must be an http(s) URL or data URI (same for video_url / audio_url)Unsupported URL scheme, including mm_file://
MiniMax-H3 does not support extrametadata.extra sent to a non-Max model
invalid extra.prompt_expansion_mode: balance, supports disabled, balanced, qualityUnknown expansion mode
invalid metadata: ...A metadata key has the wrong JSON type

Failures that happen after a successful submission — content moderation, an asset that cannot be downloaded, a cancelled or timed-out task — never appear as HTTP errors. They show up on the task record as FAILURE with a fail_reason, and the reservation is refunded.

  • The paths are RouteAPI’s: POST /v1/video/generations and GET /v1/video/generations/{task_id}. MiniMax’s /v2/video_generation and /v2/query/video_generation/{id} are not exposed, so swapping the base URL in an official SDK does not work.
  • The prompt goes in the top-level prompt, and MiniMax’s content array goes in metadata.content. RouteAPI builds the upstream content, including the text item, and the first-frame / last-frame shortcuts through images have no MiniMax equivalent.
  • The task_id you receive is RouteAPI’s. MiniMax’s own task ID only appears in data.data.task.id.
  • RouteAPI validates the item types, roles, counts and URL schemes before forwarding — stricter than MiniMax, which leaves most of it to the generation step.
  • Only model, content, resolution, duration, ratio, aigc_watermark and extra are forwarded. Other MiniMax parameters, callback_url included, are dropped.
  • Media must be public http(s) or data: URLs; MiniMax mm_file:// file IDs cannot be used.
  • resolution and duration are filled in by RouteAPI when omitted (768P, 5 s), so the upstream always receives explicit values.
  • On success RouteAPI stores MiniMax’s content.url as result_url; there is no separate file-retrieval step to call.

Needs bash, curl and jq. It submits a 5-second text-to-video task, polls every 15 seconds for up to 30 minutes, downloads the result (adding Authorization only for the RouteAPI proxy form) and prints the billed usage.

#!/usr/bin/env bash
set -euo pipefail
: "${ROUTEAPI_KEY:?export ROUTEAPI_KEY first}"
BASE="${ROUTEAPI_BASE:-https://api.routeapi.ai}"
AUTH="Authorization: Bearer $ROUTEAPI_KEY"
TASK_ID=$(curl -sS -X POST "$BASE/v1/video/generations" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "A paper boat drifting down a rain-soaked street, cinematic lighting",
"resolution": "768P",
"ratio": "16:9",
"duration": 5
}' | jq -er '.task_id')
echo "task: $TASK_ID"
for _ in $(seq 1 120); do
RESP=$(curl -sS "$BASE/v1/video/generations/$TASK_ID" -H "$AUTH")
STATUS=$(jq -r '.data.status // empty' <<<"$RESP")
echo "status: ${STATUS:-unknown} $(jq -r '.data.progress // ""' <<<"$RESP")"
case "$STATUS" in
SUCCESS)
URL=$(jq -r '.data.result_url' <<<"$RESP")
OUT="$TASK_ID.mp4"
if [[ "$URL" == *"/v1/videos/"*"/content" ]]; then
curl -sSL -o "$OUT" -H "$AUTH" "$URL"
else
curl -sSL -o "$OUT" "$URL"
fi
echo "saved: $OUT"
jq -r '.data.data.task.usage // {}' <<<"$RESP"
exit 0
;;
FAILURE)
echo "failed: $(jq -r '.data.fail_reason' <<<"$RESP")" >&2
exit 1
;;
esac
sleep 15
done
echo "gave up after 30 minutes" >&2
exit 1

MiniMax-Hailuo-2.3 and MiniMax-Hailuo-2.3-Fast use MiniMax’s /v1/video_generation API and are priced per task, not per second. RouteAPI submits, polls /v1/query/video_generation, then resolves the result through MiniMax’s /v1/files/retrieve and stores the download URL in result_url.

Model IDNotes
MiniMax-Hailuo-2.3Text-to-video and image-to-video
MiniMax-Hailuo-2.3-FastFaster, cheaper variant of 2.3

Both default to 768P and 6 seconds. The Task API does not range-check resolution or duration for this family beyond the shared 0–3600 limit: values are forwarded and MiniMax decides. The console playground offers 768P / 1080P and 6 or 10 seconds, with 1080P limited to 6 seconds.

Envelope fieldWhat the adaptor does
promptSent as prompt; metadata.prompt overrides it
durationSent as duration; omitted or 0 becomes 6
sizeConverted to resolution by substring: 1080 → 1080P, 768 → 768P, 720 → 720P, 512 → 512P; anything else falls back to the model default
images / imageNot read. Image input must go through metadata.first_frame_image
ratio, generate_audio, secondsNot read. This family has no aspect-ratio or soundtrack parameter
metadataDecoded into MiniMax’s fields using MiniMax’s names

resolution is not read from the top level for this family: use size or metadata.resolution.

These go under metadata. A value of the wrong JSON type (for example "duration": "abc") fails the conversion with 500 build_request_failed, not 400; unknown keys are ignored.

FieldTypeDescription
resolutionstring768P or 1080P; overrides whatever size produced
durationinteger6 or 10 seconds; overrides the top-level duration
first_frame_imagestringFirst-frame image (public URL or base64 data: URI), forwarded as sent
last_frame_imagestringLast frame for start-end-to-video, forwarded as sent
subject_referencearraySubject reference for subject-reference-to-video: [{"type": "character", "image": ["<url>"]}]
prompt_optimizerbooleanLet MiniMax rewrite the prompt; an explicit false is forwarded
fast_pretreatmentbooleanMiniMax fast pre-treatment flag, forwarded as sent
aigc_watermarkbooleanAdd the provider’s AIGC watermark
callback_urlstringForwarded to MiniMax. RouteAPI does not register or receive callbacks — poll for the result
promptstringOverrides the top-level prompt

metadata.model is overwritten with the channel’s upstream model name, so a request cannot switch to a different model through metadata.

Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-Hailuo-2.3",
"prompt": "The camera slowly pushes in as the subject looks up and smiles",
"duration": 6,
"metadata": {
"resolution": "1080P",
"first_frame_image": "https://cdn.example.com/first.jpg"
}
}'

MiniMax v1 reports Preparing, Queueing, Processing, Success and Fail.

Upstream statusTask record statusProgress
Preparing, QueueingIN_PROGRESS30%
ProcessingIN_PROGRESS50%
SuccessSUCCESS100%
FailFAILURE100%

On success the adaptor calls MiniMax’s file-retrieval endpoint for the returned file_id and stores the resulting download URL in result_url. That URL expires on MiniMax’s schedule; GET /v1/videos/{task_id}/content streams the stored URL through RouteAPI and needs Authorization.

The 2.3 family is charged the model’s task price configured in the console. The resolution and duration you send do not change the charge, and there is no completion-time settlement; a failed task refunds the reservation. X-New-Api-Other-Ratios is {}.

StatuscodeMeaning
400invalid_requestMissing or blank prompt, or malformed JSON
400invalid_secondsduration / seconds is negative or above 3600
400MiniMax’s numeric codeMiniMax rejected the task; the message is its status_msg
400task_not_existThe task_id is unknown or belongs to another account
500build_request_failed, do_request_failedMetadata conversion failed, or the upstream was unreachable
500unmarshal_response_body_failedMiniMax answered in a shape the adaptor does not recognize
502upstream_task_id_missingThe submit response carried no task ID
upstream statusfail_to_fetch_taskMiniMax answered with a non-200 HTTP status

For this family every MiniMax business rejection is returned as 400 with MiniMax’s numeric code and status_msg, including rate limiting — check the numeric code, not the HTTP status. The exception is an upstream balance failure: when MiniMax’s status_msg matches RouteAPI’s built-in billing keywords (insufficient balance and similar), the response is sanitized to 503 get_channel_failed with a generic message, and the failure is recorded as a channel fault (the channel is auto-disabled only when automatic disabling is enabled and the channel allows it).

Failures after submission (moderation, provider timeout) appear on the task record as FAILURE with a fail_reason, and the pre-charged amount is refunded.