Aller au contenu

MiniMax Hailuo

Hailuo est la famille de génération vidéo de MiniMax. Un même canal sert deux générations d’API : MiniMax-H3 et MiniMax-H3-Max utilisent l’API /v2 de MiniMax avec un tableau content et sont réglés à la seconde, tandis que la famille MiniMax-Hailuo-2.3 utilise l’ancienne API /v1 avec un prix fixe par tâche (traité en fin de page).

Les tâches sont soumises, interrogées et téléchargées via les endpoints communs décrits dans Créer une tâche et Consulter une tâche. Cette page décrit ce que ce fournisseur lit, comment la requête est construite et comment elle est facturée.

ID du modèleRésolutionsDurée (secondes entières)Valeurs par défautExtension de prompt
MiniMax-H3768P, 2K4–15768P, 5 sNon
MiniMax-H3-Max480P, 768P5–15768P, 5 sOui
  • L’ID du modèle est sensible à la casse : recopiez-le tel qu’il figure ci-dessus. Votre compte ne peut utiliser que les modèles routés vers lui, et le prix dépend du compte ; GET /v1/models fait foi pour votre clé.
  • MiniMax-H3-Max est le seul modèle à accepter extra. Envoyer extra à MiniMax-H3 renvoie 400.
  • Les deux modèles prennent en charge le texte vers vidéo, la première image, la première et la dernière image, ainsi que les images, vidéos et audios de référence.
ChampTypeRequisDéfautDescription
modelstringOui—ID du modèle issu de GET /v1/models
promptstringOui—Prompt ; vide après suppression des espaces, il est rejeté. 7000 caractères max
resolutionstringNon768PInsensible à la casse ; doit être l’une des résolutions du modèle
durationintegerNon5Secondes entières dans la plage du modèle
secondsstringNon—Forme chaîne de la durée ; lu seulement si duration est absent ou 0
ratiostringNonvoir plus basRatio d’image
imagesstring[]Non—1 image = première image ; 2 images = première puis dernière. 2 au maximum
imagestringNon—Image unique ; utilisée seulement si images est vide
metadataobjectNon—Paramètres MiniMax, voir la section suivante

Règles de priorité :

  • metadata.resolution, metadata.duration et metadata.ratio remplacent les champs de premier niveau du même nom.
  • seconds n’est lu que si le duration de premier niveau est absent ou 0, et metadata.duration l’emporte sur les deux.
  • metadata.duration est analysé comme un nombre : 5.5 échoue avec invalid duration. Contrairement au duration de premier niveau, 0 n’y signifie pas « non défini » mais « hors plage ». Omissez la clé pour garder la valeur par défaut.
  • size n’est pas pris en charge. Un size de premier niveau ou metadata.size renvoie MiniMax-H3 请使用 resolution(480P/768P/2K),不支持 size ; utilisez resolution.
  • Hormis size, les champs de premier niveau que ce fournisseur ne lit pas (par exemple generate_audio ou input_reference) sont ignorés plutôt que rejetés.
ChampTypeDescription
contentarrayMatériel d’entrée, voir Éléments content et limites. Incompatible avec images / image de premier niveau
resolutionstringRemplace le resolution de premier niveau
durationnumberRemplace duration et seconds de premier niveau ; doit être un entier dans la plage
ratiostringRemplace le ratio de premier niveau
aigc_watermarkboolean ou stringtrue / false. Les chaînes "true" / "false" sont aussi acceptées, c’est ce qu’envoient les formulaires multipart. Omis, l’upstream décide
extra.prompt_expansion_modestringdisabled, balanced ou quality. MiniMax-H3-Max uniquement
size—Rejeté avec 400

metadata est décodé dans une structure typée : un type JSON erroné sur l’une des clés ci-dessus (par exemple "duration": "abc", ou content en objet) renvoie 400 avec invalid metadata: ... et rien n’est facturé. Les clés absentes du tableau — seed, callback_url, etc. — sont ignorées et n’atteignent jamais MiniMax ; aucun callback n’est envoyé, interrogez la tâche pour obtenir le résultat.

Valeurs acceptées : adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16. La valeur est insensible à la casse.

Forme de la requêteratio omisRègles
Texte seul (sans images ni références)16:9adaptive est rejeté avec text-to-video does not support ratio adaptive
Première image, ou première et dernièreadaptiveForcé à adaptive ; toute valeur envoyée est ignorée et non validée
Matériel de référenceadaptiveN’importe laquelle des sept valeurs

metadata.content est un tableau ordonné. Chaque élément a un type, un champ de charge utile correspondant à ce type, et un role facultatif :

typeCharge utilerole autorisésLimite
texttextaucun1, et doit être égal à prompt
image_urlimage_url.urlfirst_frame1
image_urlimage_url.urllast_frame1, et exige first_frame
image_urlimage_url.urlreference_image9
image_urlimage_url.urlaucununiquement comme unique média
video_urlvideo_url.urlreference_video (obligatoire)3
audio_urlaudio_url.urlreference_audio (obligatoire)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://..." } }

Règles vérifiées avant l’envoi :

  • Au plus 12 éléments multimédias par requête, dont au plus 9 images de référence, 3 vidéos de référence et 3 audios de référence.
  • Les images de première / dernière image et le matériel de référence ne se mélangent pas. reference_image, reference_video et reference_audio se combinent librement.
  • Un élément image_url sans role n’est autorisé que s’il est le seul média ; il est alors traité comme first_frame.
  • Si content ne contient aucun élément text, RouteAPI en ajoute un en tête avec le prompt de premier niveau. S’il en contient un, il doit être unique et son texte doit être égal au prompt débarrassé des espaces, sinon la requête échoue avec prompt 与 metadata.content 中的 text 冲突.
  • content et les images / image de premier niveau s’excluent.
  • Seul le champ correspondant au type de l’élément est transmis ; les clés superflues sont supprimées.
  • Les URL de média — y compris les images / image de premier niveau — doivent être des URI http://, https:// ou data: (par exemple data:image/png;base64,...) et être téléchargeables sans authentification. Les IDs de fichier MiniMax (mm_file://) ne sont pas pris en charge. Les URL que MiniMax cite dans un refus sont remplacées par [url omitted], de sorte qu’aucun lien signé n’apparaît dans les messages d’erreur.
  • Les limites de format, dimension, durée et taille de chaque média sont celles de MiniMax ; RouteAPI ne les vérifie pas. Un média non conforme est rejeté soit à la soumission (400, rien n’est facturé), soit pendant la génération (la tâche passe en FAILURE et la réservation est remboursée).
Fenêtre de terminal
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
}'
Fenêtre de terminal
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
}'

Les deux entrées de images deviennent first_frame et last_frame. ratio est forcé à adaptive.

Fenêtre de terminal
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
}'

Utilisez metadata.content dès que vous avez besoin de plus de deux images ou d’une vidéo ou d’un audio de référence. Les vidéos de référence sont facturées : gardez-les entre 2 et 15 secondes — voir Facturation.

Fenêtre de terminal
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" } }
]
}
}'
Fenêtre de terminal
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" }
}
}'
task.status MiniMaxdata.statusdata.progress
queuedQUEUED20%
runningIN_PROGRESS50%
succeeded avec content.urlSUCCESS100%
succeeded sans content.urlFAILURE100%
failed, cancelledFAILURE100%
toute autre valeurIN_PROGRESS30%

Une tâche succeeded sans URL vidéo est considérée comme échouée avec fail_reason upstream succeeded without video url, et la réservation est remboursée. Une tâche failed ou cancelled remonte le task.error.message de MiniMax (chaque URL est remplacée par [url omitted]) ; sans message, la raison est task failed ou task cancelled.

Une réponse de polling qui est une enveloppe d’erreur ({"type":"error","error":{...}}) fait échouer ce cycle et la tâche est interrogée de nouveau. Un corps sans aucun objet tâche retombe sur l’ancien format /v1, qui est vide, donc la tâche reste simplement en IN_PROGRESS. Une tâche qui n’atteint jamais un état terminal est déclarée en échec par le délai de garde de la plateforme — 24 heures par défaut — avec fail_reason 任务超时(1440分钟), et la réservation est remboursée.

GET /v1/video/generations/{task_id} renvoie la ligne de tâche RouteAPI ; Consulter une tâche documente tous les champs. Pour ce fournisseur, les champs utiles sont :

ChampDescription
data.status / data.progressÉtat et progression de la tâche, d’après le tableau ci-dessus
data.result_urlURL de la vidéo une fois la tâche réussie
data.fail_reasonRaison de l’échec, vide sinon
data.quotaQuota facturé pour cette tâche
data.properties.inputCopie de la requête envoyée à l’upstream, URL de média remplacées par [omitted, N bytes] ; utile en cas de contestation de facture
data.dataDernière réponse de MiniMax
{
"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
}
}
}
}
}

Champs internes utiles :

ChampDescription
data.data.task.idID de tâche MiniMax, différent du task_id RouteAPI
data.data.task.statusqueued, running, succeeded, failed ou cancelled
data.data.task.content.urlURL de la vidéo en cas de succès ; c’est elle que contient result_url
data.data.task.resolutionRésolution rapportée par MiniMax. La facturation utilise celle demandée, pas celle-ci
data.data.task.usage.output_secondsDurée du rendu, utilisée pour le règlement
data.data.task.usage.input_secondsDurée de la vidéo de référence, utilisée pour le règlement
data.data.task.usage.input_image_countNombre d’images rapporté par MiniMax ; le règlement utilise le nombre soumis
data.data.task.error.code / .messageDétail de l’échec lorsque MiniMax en fournit un

Avant le premier polling réussi, data.data est la réponse brute de soumission ({"task_id": "..."}) et n’a pas de champ task. task.usage apparaît lorsque MiniMax le renvoie, généralement en cas de succès. Branchez toujours votre logique sur le data.status externe.

data.result_url pointe déjà vers le CDN de MiniMax. Ce lien expire selon le calendrier de MiniMax : téléchargez-le dès que la tâche passe en SUCCESS.

  • Lien CDN direct : récupérez-le sans en-tête Authorization ; certains stockages refusent les en-têtes d’authentification superflus.
  • https://api.routeapi.ai/v1/videos/{task_id}/content : diffuse la même URL stockée via RouteAPI et exige Authorization: Bearer $ROUTEAPI_KEY. Il récupère à chaque fois le lien stocké et ne prolonge donc pas l’expiration. À utiliser lorsque votre client ne doit pas voir l’hôte upstream, ou lorsque le CDN refuse l’accès direct. Il répond 404 Task not found pour une tâche inconnue et 400 Task is not completed yet, current status: ... tant que la tâche n’a pas réussi.
Fenêtre de terminal
# 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"

La facturation à la seconde s’applique lorsque le modèle a un prix fixe configuré pour votre compte (la page de détail du modèle dans la console l’affiche). Si le modèle n’est tarifé que par ratio de modèle, la facturation habituelle par tâche s’applique et il n’y a pas de règlement à l’achèvement. Avec la facturation à la seconde, le montant se compose de trois éléments :

ÉlémentPrix unitaireCompté à la soumission (réservation)Compté au règlement
Vidéo de sortieà la seconde, pour la résolution demandéele duration demandémin(usage.output_seconds, duration)
Entrée vidéo de référenceà la seconde, pour la résolution demandée15 s dès que content contient une reference_videousage.input_seconds, valide seulement entre 2 et 15 s
Imagespar image au-delà du quota gratuitchaque élément image de content construit, images fixes inclusesle même nombre, depuis la copie de la soumission

Les prix et le quota d’images gratuites sont configurés par compte ; les valeurs intégrées autorisent 5 images gratuites sur MiniMax-H3 et 2 sur MiniMax-H3-Max, mais la console fait foi. Aucun prix n’est indiqué sur cette page.

MomentSecondes de sortieSecondes de vidéo de référence
Réservé à la soumissionle duration demandé15 s si la requête contient une vidéo de référence
Réglé en cas de succèsusage.output_seconds, plafonné au duration demandéusage.input_seconds lorsqu’il est compris entre 2 et 15 s

Règles :

  • Le règlement ne fait que rembourser : le débit final est le plus petit du montant recalculé et de la réservation.
  • Le règlement utilise les prix unitaires figés à la soumission. Un changement de prix pendant l’exécution n’affecte pas la tâche.
  • Sans vidéo de référence, il n’y a aucun élément « secondes d’entrée » et usage.input_seconds est ignoré.
  • L’audio de référence est gratuit, et l’élément images ne change pas au règlement.
  • Comme une requête avec vidéo de référence réserve 15 s d’entrée, le solde doit couvrir ce pire cas même si la vidéo est plus courte.
  • Si usage manque, si output_seconds vaut 0 ou dépasse 15, ou (avec une vidéo de référence) si input_seconds manque ou sort de 2–15, RouteAPI conserve toute la réservation et ne rembourse rien. Gardez vos vidéos de référence entre 2 et 15 secondes pour l’éviter.
  • Une tâche échouée ou expirée rembourse toute la réservation ; une requête rejetée en 400 n’est jamais facturée.
  • En facturation à la seconde, l’en-tête X-New-Api-Other-Ratios de la réponse de soumission porte le multiplicateur appliqué au prix du modèle sous la clé h3_units (une tâche de 5 s en 768P donne {"h3_units": 5}). Il vaut {} pour la famille 2.3 et pour un modèle H3 sans prix fixe.

Prix hypothétiques, uniquement pour l’arithmétique : MiniMax-H3 en 768P coûte 0,10 $ par seconde de sortie, 0,10 $ par seconde de vidéo de référence et 0,04 $ par image au-delà de 5 images gratuites. Une requête de 10 secondes avec deux images de référence et une vidéo de référence :

  • Réservation : 10 × 0,10 (sortie) + 15 × 0,10 (vidéo de référence, plafonnée) + max(0, 2 − 5) × 0,04 (images) = 2,50 $.
  • MiniMax renvoie output_seconds: 8 et input_seconds: 6 : 8 × 0,10 + 6 × 0,10 + 0 = 1,40 $.
  • La différence, 1,10 $, est restituée au solde.

La soumission est validée avant toute réservation, donc un 400 ne coûte rien. Les refus métier de MiniMax arrivent dans une réponse HTTP 200 et sont convertis ainsi :

base_resp.status_code MiniMaxSignificationHTTP renvoyécode
1026Refus de contenu / sécurité4001026
2013Erreur de paramètre4002013
1002Limitation de débit4291002
1004, 2049Échec de clé / auth upstream401, généralement renvoyé en 5031004 / 2049, ou get_channel_failed
1008Solde upstream épuisé503get_channel_failed
tout autre codeErreur métier inconnue502le code numérique
— (corps illisible, ou enveloppe type: "error")Réponse de soumission malformée502invalid_response
— (task_id vide)Aucun ID de tâche upstream502upstream_task_id_missing

Les échecs de compte upstream ne sont jamais renvoyés tels quels. L’adaptateur convertit 1008 en 402 et 1004 / 2049 en 401 ; RouteAPI classe ensuite la défaillance comme une panne de canal et répond 503 get_channel_failed avec un message générique « service amont temporairement indisponible », après avoir essayé un autre canal s’il en existe un. Le 402 de 1008 est renvoyé en 503 pour la même raison. Le status_msg de MiniMax ne vous parvient jamais dans ces cas. Un 429 conserve son statut mais son message est remplacé par un avis de saturation générique. Un 400 contient le texte de MiniMax préfixé par hailuo api error: .

Si MiniMax répond avec un statut HTTP autre que 200, le corps n’est pas analysé : vous recevez le code fail_to_fetch_task avec ce statut. Interroger un task_id inconnu ou appartenant à un autre compte renvoie 400 avec le code task_not_exist.

Les erreurs produites avant que la requête n’atteigne MiniMax suivent les règles communes de Erreurs courantes : 401 pour une API Key absente ou invalide, 403 insufficient_user_quota lorsque le solde ne couvre pas la réservation (y compris le pire cas des 15 s de vidéo de référence), et 403 avec This token has no access to model ... lorsque la clé n’a pas accès au modèle.

Messages 400 fréquents (code invalid_request sauf mention contraire) :

messageCause
prompt is requiredprompt absent ou vide
seconds must be between 1 and 3600 (code invalid_seconds)Le duration de premier niveau est négatif ou dépasse 3600
invalid seconds: abcseconds n’est pas une chaîne entière
<model> 请使用 resolution(480P/768P/2K),不支持 sizesize a été envoyé au premier niveau ou dans metadata ; le message nomme votre modèle et liste toujours 480P/768P/2K
invalid resolution: 1080P, MiniMax-H3 supports 768P, 2KRésolution non prise en charge par ce modèle
invalid duration: 3, MiniMax-H3 supports integer 4-15Durée sous le minimum, au-dessus de 15, ou non entière
invalid ratio: 2:1, supports adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16Ratio absent de la liste
text-to-video does not support ratio adaptiveadaptive sur une requête sans image ni référence
at most 2 top-level images (first_frame, last_frame), got 3; use metadata.content for reference mediaPlus de 2 entrées dans images
images must not contain empty valuesEntrée vide dans images
metadata.content cannot be combined with top-level imagesLes deux ont été envoyés
metadata.content must be a non-empty arraycontent vaut []
prompt 与 metadata.content 中的 text 冲突L’élément text diffère du prompt
metadata.content accepts at most one text itemPlus d’un élément text
text exceeds 7000 charactersPrompt de plus de 7000 caractères
invalid content type "foo"type inconnu
invalid role "foo" for image_urlrole d’image inconnu
image_url without role is only allowed as the single input imageImage sans role mélangée à d’autres médias
last_frame requires first_frameSeule une dernière image a été envoyée
at most one first_frame and one last_frameRôles de cadre en double
first/last frame images cannot be combined with reference mediaCadres mélangés à du matériel de référence
at most 9 reference images / at most 3 reference videos / at most 3 reference audios / at most 12 media itemsLimite par type ou totale de médias dépassée
video_url requires role reference_video / audio_url requires role reference_audiorole erroné ou absent pour ce type d’élément
image_url.url must be an http(s) URL or data URI (idem video_url / audio_url)Schéma d’URL non pris en charge, dont mm_file://
MiniMax-H3 does not support extrametadata.extra envoyé à un modèle non-Max
invalid extra.prompt_expansion_mode: balance, supports disabled, balanced, qualityMode d’extension inconnu
invalid metadata: ...Une clé metadata a un type JSON erroné

Les échecs survenant après une soumission réussie — modération, média non téléchargeable, tâche annulée ou expirée — n’apparaissent jamais comme erreurs HTTP. Ils apparaissent sur l’enregistrement de tâche en FAILURE avec un fail_reason, et la réservation est remboursée.

  • Les chemins sont ceux de RouteAPI : POST /v1/video/generations et GET /v1/video/generations/{task_id}. Les /v2/video_generation et /v2/query/video_generation/{id} de MiniMax ne sont pas exposés ; changer le Base URL d’un SDK officiel ne suffit donc pas.
  • Le prompt va dans prompt de premier niveau et le tableau content de MiniMax va dans metadata.content. RouteAPI construit le content upstream, y compris l’élément text, et les raccourcis première / dernière image via images n’ont pas d’équivalent chez MiniMax.
  • Le task_id que vous recevez est celui de RouteAPI. L’ID de tâche MiniMax n’apparaît que dans data.data.task.id.
  • RouteAPI valide les types d’éléments, les rôles, les nombres et les schémas d’URL avant de transmettre — plus strict que MiniMax, qui laisse l’essentiel à l’étape de génération.
  • Seuls model, content, resolution, duration, ratio, aigc_watermark et extra sont transmis. Les autres paramètres MiniMax, callback_url compris, sont supprimés.
  • Les médias doivent être des URL publiques http(s) ou data: ; les IDs de fichier mm_file:// de MiniMax sont inutilisables.
  • resolution et duration sont complétés par RouteAPI quand ils manquent (768P, 5 s), l’upstream reçoit donc toujours des valeurs explicites.
  • En cas de succès, RouteAPI enregistre le content.url de MiniMax comme result_url ; il n’y a pas d’étape de récupération de fichier séparée à appeler.

Nécessite bash, curl et jq. Il soumet une tâche texte vers vidéo de 5 secondes, interroge toutes les 15 secondes pendant 30 minutes au plus, télécharge le résultat (en ajoutant Authorization uniquement pour la forme proxy RouteAPI) et affiche l’usage facturé.

#!/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 et MiniMax-Hailuo-2.3-Fast utilisent l’API /v1/video_generation de MiniMax et sont facturés par tâche, pas à la seconde. RouteAPI soumet, interroge /v1/query/video_generation, puis résout le résultat via /v1/files/retrieve de MiniMax et stocke l’URL de téléchargement dans result_url.

ID du modèleRemarques
MiniMax-Hailuo-2.3Texte vers vidéo et image vers vidéo
MiniMax-Hailuo-2.3-FastVariante plus rapide et moins chère du 2.3

Les deux valent par défaut 768P et 6 secondes. L’API de tâche ne vérifie ni la résolution ni la durée de cette famille au-delà de la limite commune 0–3600 : les valeurs sont transmises et MiniMax décide. Le playground de la console propose 768P / 1080P et 6 ou 10 secondes, 1080P étant limité à 6 secondes.

Champ de l’enveloppeCe que fait l’adaptateur
promptEnvoyé comme prompt ; metadata.prompt le remplace si présent
durationEnvoyé comme duration ; absent ou 0 devient 6
sizeConverti en resolution par sous-chaîne : 1080 → 1080P, 768 → 768P, 720 → 720P, 512 → 512P ; toute autre valeur retombe sur le défaut du modèle
images / imageNon lus. L’entrée image doit passer par metadata.first_frame_image
ratio, generate_audio, secondsNon lus. Cette famille n’a pas de paramètre de ratio ni de bande-son
metadataDécodé dans les champs MiniMax, avec les noms de MiniMax

resolution n’est pas lu au premier niveau pour cette famille : utilisez size ou metadata.resolution.

Ils vont sous metadata. Une valeur du mauvais type JSON (par exemple "duration": "abc") fait échouer la conversion avec 500 build_request_failed, pas 400 ; les clés inconnues sont ignorées.

ChampTypeDescription
resolutionstring768P ou 1080P ; remplace ce que size a produit
durationinteger6 ou 10 secondes ; remplace le duration de premier niveau
first_frame_imagestringPremière image (URL publique ou URI data: base64), transmise telle quelle
last_frame_imagestringDernière image pour la génération première-fin, transmise telle quelle
subject_referencearrayRéférence de sujet : [{"type": "character", "image": ["<url>"]}]
prompt_optimizerbooleanLaisse MiniMax réécrire le prompt ; un false explicite est transmis
fast_pretreatmentbooleanIndicateur de prétraitement rapide de MiniMax, transmis tel quel
aigc_watermarkbooleanAjoute le filigrane AIGC du fournisseur
callback_urlstringTransmis à MiniMax. RouteAPI n’enregistre ni ne reçoit de callback — interrogez la tâche
promptstringRemplace le prompt de premier niveau

metadata.model est écrasé par le nom du modèle upstream du canal : une requête ne peut donc pas basculer vers un autre modèle via metadata.

Fenêtre de terminal
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 renvoie Preparing, Queueing, Processing, Success et Fail.

Statut upstreamStatut de la tâcheProgression
Preparing, QueueingIN_PROGRESS30%
ProcessingIN_PROGRESS50%
SuccessSUCCESS100%
FailFAILURE100%

En cas de succès, l’adaptateur appelle l’endpoint de récupération de fichier de MiniMax avec le file_id renvoyé et stocke l’URL de téléchargement obtenue dans result_url. Cette URL expire selon le calendrier de MiniMax ; GET /v1/videos/{task_id}/content diffuse l’URL stockée via RouteAPI et exige Authorization.

La famille 2.3 est facturée au prix de tâche configuré dans la console. La résolution et la durée envoyées ne changent pas le montant, et il n’y a pas de règlement à l’achèvement ; une tâche échouée rembourse la réservation. X-New-Api-Other-Ratios vaut {}.

StatutcodeSignification
400invalid_requestprompt absent ou vide, ou JSON malformé
400invalid_secondsduration / seconds négatif ou supérieur à 3600
400Code numérique de MiniMaxMiniMax a refusé la tâche ; le message est son status_msg
400task_not_existLe task_id est inconnu ou appartient à un autre compte
500build_request_failed, do_request_failedConversion des metadata échouée, ou upstream injoignable
500unmarshal_response_body_failedMiniMax a répondu dans une forme que l’adaptateur ne reconnaît pas
502upstream_task_id_missingLa réponse de soumission ne contenait aucun ID de tâche
statut upstreamfail_to_fetch_taskMiniMax a répondu avec un statut HTTP autre que 200

Pour cette famille, tous les refus métier de MiniMax reviennent en 400, limitation de débit comprise, avec le code numérique et le status_msg tels quels : fiez-vous au code numérique, pas au statut HTTP. L’exception est un solde upstream épuisé : lorsque le status_msg de MiniMax correspond aux mots-clés de facturation intégrés à RouteAPI (solde insuffisant, etc.), la réponse est assainie en 503 get_channel_failed avec un message générique, et l’échec est enregistré comme une panne de canal (le canal n’est désactivé automatiquement que si la désactivation automatique est activée et que le canal l’autorise).

Les échecs après soumission (modération, délai dépassé côté fournisseur) apparaissent sur l’enregistrement de tâche en FAILURE avec un fail_reason, et le montant prélevé est remboursé.