Tutoriel
Comment utiliser l'API Ray 3.2 text-to-video : curl, Python et une requête directement exécutable
Ray 3.2 est un modèle text-to-video du catalogue de modèles hiapi. Comme tous les autres modèles vidéo, il s'appelle via l'API de tâches asynchrones unifiée — l'id du modèle est ray-3.2/text-to-video, soumis à POST /v1/tasks. Contrairement à certains modèles vidéo dont le seul réglage possible est le prompt, Ray 3.2 offre trois véritables contrôles de sortie — duration, resolution et aspect_ratio — chacun étant strictement validé côté serveur.
Ce guide vous permet d'envoyer une requête réussie du premier coup : le schéma d'entrée exact (vérifié contre l'API en production le 2026-10-19), un appel curl prêt à copier-coller, un script Python complet de soumission/polling/téléchargement, ainsi que les détails de production — callbacks, nouvelles tentatives idempotentes et les réponses d'erreur que vous verrez réellement.
Ce que vous allez construire et ce qu'il faut préparer
Objectif : soumettre un prompt textuel, interroger la tâche en boucle et télécharger un clip .mp4 muet (5 ou 10 secondes).
Prérequis :
- Une clé API hiapi — à récupérer depuis votre console. La clé ressemble à
sk-...et se place dans l'en-têteAuthorization: Bearer. Vous découvrez l'API de tâches ? Commencez par le guide de démarrage rapide. - N'importe quel client HTTP. Nous montrerons
curlet Python (requests).
La sortie de Ray 3.2 est facturée au clip, et le prix augmente fortement selon vos choix — consultez les tarifs actuels sur la page de tarification. Pendant l'itération sur le prompt, partez de 540p / 5 secondes ; un clip 1080p de 10 secondes peut coûter plusieurs fois le prix d'un rendu d'image de taille budgétaire, alors ne laissez pas votre boucle de développement tourner en permanence sur les réglages les plus élevés.
Le schéma d'entrée exact (un champ obligatoire, trois énumérations strictes)
Tout se trouve dans un objet input. Vérifié champ par champ contre l'API en production :
| Champ | Type | Obligatoire | Valeurs autorisées | Valeur par défaut |
|---|---|---|---|---|
prompt |
string | Oui | Description de la scène, 6000 caractères maximum | — |
duration |
integer | Non | 5 ou 10 |
5 |
resolution |
string | Non | 540p, 720p, 1080p |
540p |
aspect_ratio |
string | Non | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 |
16:9 |
Avant d'écrire du code, trois choses méritent d'être retenues :
durationest un entier, pas une chaîne. Envoyez un nombre brut —"duration": 5. C'est l'inverse de certains autres modèles vidéo de l'API de tâches (par exemple hailuo-2.3 exige"duration": "6"en tant que chaîne). Si vous portez un corps de requête d'un modèle à un autre, revérifiez ce champ ; c'est l'erreur inter-modèles la plus fréquente.- Les valeurs d'énumération sont validées, pas tronquées. Les valeurs hors limites sont rejetées avec un
400, plutôt que silencieusement arrondies. Pas de2k, pas de480p, pas de2:1. - Pas de
prompt_optimizer,seedninegative_prompt. La composition se contrôle entièrement viaaspect_ratioet le prompt. Si vous envoyez un champ que le schéma ne reconnaît pas, attendez-vous à un 400 — le schéma d'entrée de/v1/tasksvarie d'un modèle à l'autre, donc ne supposez pas que des clés valides ailleurs fonctionneront ici.
Ce que la validation renvoie réellement
Voici les véritables réponses du point de terminaison en production (valeurs invalides soumises volontairement, aucune tâche créée, aucune facturation) :
// POST with "resolution": "2k"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: resolution: value must be one of '540p', '720p', '1080p'"}
// POST with "duration": 7
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: duration: value must be one of 5, 10"}
// POST with "aspect_ratio": "2:1"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: aspect_ratio: value must be one of '16:9', '9:16', '1:1', '4:3', '3:4', '21:9'"}
message indique le champ exact et l'ensemble exact des valeurs autorisées — donc si vous oubliez une valeur d'énumération, l'API vous le dira. Notez que pour duration, 5, 10 n'a pas de guillemets (des nombres), tandis que pour resolution, '540p' est une chaîne entre guillemets : cette différence de guillemets vous rappelle quel champ est un entier.
Exemple minimal exécutable : curl
Créer une tâche :
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "ray-3.2/text-to-video",
"input": {
"prompt": "Par une nuit pluvieuse, une danseuse de rue tournoie sous les néons, les flaques reflètent des lumières roses et bleues, sa veste vole au rythme de ses rotations, la caméra tourne autour d'elle en contre-plongée, rendu cinématographique",
"duration": 5,
"resolution": "540p",
"aspect_ratio": "9:16"
}
}'
La réponse de création contient un id de tâche (tronqué) :
{ "data": { "taskId": "task_01k..." } }
Interrogez-la en boucle jusqu'à l'état terminal :
curl -s https://api.hiapi.ai/v1/tasks/task_01k... \
-H "Authorization: Bearer sk-YOUR_KEY"
Pendant l'exécution de la tâche, data.status rapporte un état en cours. Les deux états terminaux sont success et fail. En cas de succès (tronqué) :
{
"data": {
"taskId": "task_01k...",
"status": "success",
"output": [ { "url": "https://.../clip.mp4" } ]
}
}
Téléchargez immédiatement data.output[0].url. Les URL de sortie sont signées et expirent — enregistrez les octets dans votre propre stockage plutôt que de faire du hotlink sur l'URL de la tâche. Ray 3.2 renvoie un MP4 muet (aucune piste audio), donc n'attendez pas un flux audio qui n'arrivera jamais.
Script Python complet (soumission → interrogation → téléchargement)
import time
import requests
API_BASE = "https://api.hiapi.ai/v1"
API_KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
def create_task(prompt: str, duration: int = 5,
resolution: str = "540p", aspect_ratio: str = "9:16") -> str:
resp = requests.post(
f"{API_BASE}/tasks",
headers=HEADERS,
json={
"model": "ray-3.2/text-to-video",
"input": {
"prompt": prompt,
"duration": duration, # 5 or 10 — an INTEGER, not a string
"resolution": resolution, # "540p" | "720p" | "1080p"
"aspect_ratio": aspect_ratio, # "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"
},
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 900, poll_interval: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(f"{API_BASE}/tasks/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
task = resp.json()["data"]
if task["status"] == "success":
return task
if task["status"] == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
time.sleep(poll_interval) # any non-terminal status = still running
raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")
task_id = create_task(
"Un bateau en papier dérive le long d'une gouttière remplie d'eau de pluie, des gouttes créent des ondulations à la surface, "
"des feuilles d'automne tourbillonnent et passent, prise de vue en contre-plongée au ras de l'eau, lumière douce de ciel couvert"
)
print("task created:", task_id)
task = wait_task(task_id)
video_url = task["output"][0]["url"]
# Output URLs expire — download right away and store the bytes yourself.
video = requests.get(video_url, timeout=120).content
with open("ray32-clip.mp4", "wb") as f:
f.write(video)
print(f"saved ray32-clip.mp4 ({len(video) / 1e6:.1f} MB)")
Installez la dépendance avec pip install requests, remplacez la clé, et vous aurez un .mp4 sur le disque une fois la tâche terminée. Les tâches vidéo prennent quelques minutes, pas quelques secondes — donnez à votre boucle d'interrogation une échéance généreuse (15 minutes ci-dessus) plutôt que de supposer un retour rapide.
Considérations de production : callbacks, idempotence, erreurs
Privilégiez les callbacks au polling
Pour tout usage au-delà d'un script, enregistrez un webhook au moment de la création de la tâche plutôt que d'interroger en boucle :
{
"model": "ray-3.2/text-to-video",
"input": { "prompt": "...", "duration": 10, "resolution": "720p" },
"callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}
Avec "when": "final", hiapi appelle votre point de terminaison une fois lorsque la tâche atteint un état terminal — pas de trafic de polling, et aucune notification de fin manquée entre deux intervalles. Votre handler exécute ensuite GET /v1/tasks/<id> (ou lit le corps de la réponse livrée) pour obtenir output[0].url. Le polling reste adapté aux CLI et notebooks qui ne peuvent pas exposer de point de terminaison HTTPS.
Rendez les nouvelles tentatives idempotentes
Persistez le taskId dès que l'appel de création le renvoie. Si votre processus plante en cours de génération, reprenez en interrogeant l'id stocké — ne recréez pas la tâche, sinon vous payez pour un second rendu. Ne recréez que si la requête de création initiale elle-même a échoué avant de renvoyer un id de tâche. Comme Ray 3.2 est facturé au clip et qu'un clip en haute résolution n'est pas bon marché, une création en double est une véritable erreur de coût, pas seulement une perte de temps.
Les erreurs que vous verrez réellement
Chaque ligne ci-dessous correspond à une forme de réponse vérifiée en production :
| Symptôme | Réponse | Correctif |
|---|---|---|
| Clé manquante/invalide | 401, imbriqué {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} |
Vérifiez l'en-tête Authorization: Bearer sk-... et que la clé a bien les droits d'accès. Fournissez le request_id au support. |
| Valeur d'énumération invalide | 400 INVALID_REQUEST, plat {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} |
Lisez le champ indiqué dans message ; il liste l'ensemble exact des valeurs autorisées. |
duration envoyé en chaîne |
400 INVALID_REQUEST |
Envoyez l'entier brut 5 ou 10, pas "5". |
| Id de modèle inconnu | 400, error_code: "MODEL_UNAVAILABLE", "model not available via /v1/tasks" |
Utilisez strictement ray-3.2/text-to-video — consultez l'id canonique sur la page du modèle. |
| Id de tâche erroné lors de l'interrogation | 404, plat {"code":404,"data":null,"message":"task not found"} (note : pas de error_code sur un 404) |
Id incorrect, ou vous interrogez avec la clé d'un autre compte. |
status: "fail" lors de l'interrogation |
État terminal de la tâche, détails dans data.error |
Lisez data.error.code / data.error.message. Les tâches échouées sont remboursées ; les signalements de politique de contenu et les problèmes de capacité en amont apparaissent ici — pour un signalement de contenu, réessayez avec un prompt reformulé. |
Ressources associées
- Page du modèle Ray 3.2 text-to-video — essayez-le en ligne, statut en temps réel et grille tarifaire complète
- API Ray 3.2 image-to-video — même famille de modèles, mais elle anime une image de référence au lieu de partir du texte (schéma d'entrée différent — sondez-le avant de réutiliser ce corps de requête)
- Comment utiliser l'API Hailuo 2.3 text-to-video — une recette similaire dont le
durationest une chaîne, un contraste utile avec l'entier de Ray - Tarification hiapi — tarifs vidéo au clip par résolution et par durée
FAQ
Quel est l'id du modèle et quel point de terminaison appeler ?
ray-3.2/text-to-video, soumis comme model de premier niveau à POST https://api.hiapi.ai/v1/tasks, avec les paramètres sous input. C'est asynchrone — vous récupérez un taskId, puis vous interrogez GET /v1/tasks/<id> (ou vous enregistrez un callback).
duration est-il en secondes, et pourquoi "5" échoue-t-il ?
Les clips font 5 ou 10 secondes, et le champ est un entier : envoyez 5 ou 10. Une chaîne entre guillemets, ou tout autre nombre comme 7, échoue avec 400 INVALID_REQUEST: duration: value must be one of 5, 10.
Puis-je définir la résolution et le rapport d'aspect ?
Oui — c'est précisément ce qui distingue Ray 3.2 des modèles vidéo limités au prompt. resolution vaut 540p, 720p ou 1080p ; aspect_ratio vaut l'une des valeurs 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Les deux sont optionnels (valeurs par défaut 540p et 16:9) et rejettent les valeurs hors limites avec un 400.
Combien coûte un clip ?
Ray 3.2 est facturé au clip, et la résolution est le plus grand levier — à durée égale, un clip 1080p coûte plusieurs fois celui d'un 540p, et un clip de 10 secondes coûte environ trois fois celui de 5 secondes. Les tarifs changent, donc consultez la page de tarification plutôt que de coder un chiffre en dur, et prototypez en 540p/5 secondes.
Les clips ont-ils de l'audio ? Non — Ray 3.2 text-to-video renvoie un MP4 muet. Si vous avez besoin de son, ajoutez-le en post-production ou utilisez un modèle audio distinct.
Ray 3.2 prend-il en charge image-to-video ?
Oui, sous la forme d'un id de modèle distinct sur la même API de tâches : ray-3.2/image-to-video. Son schéma d'entrée est différent (il accepte une image de référence), donc sondez-le avant de réutiliser ce corps de requête — voir la page du modèle image-to-video.
Ma génération est lente ou semble bloquée. Qu'est-ce qui est normal ?
Les tâches vidéo prennent quelques minutes. Dans votre boucle d'interrogation, considérez tout data.status non terminal comme « en cours » et attendez — prévoyez une échéance de 10 à 15 minutes, ou utilisez un callback avec "when": "final" pour que hiapi vous notifie à l'état terminal au lieu de deviner un intervalle.
Articles similaires
Voir tous les articles →-
Tutoriel
Comment appeler hailuo-2.3-fast/image-to-video via l'API HiAPI : curl et Python en pratique
La première requête exploitable du palier image-vers-vidéo rapide et économique — de l'ID du modèle au téléchargement du MP4
-
Tutoriel
Comment appeler hailuo-2.3/text-to-video via l'API HiAPI : curl, Python et exemples de requêtes exécutables
-
Tutoriel
Utiliser Kandinsky 6.0 Pro texte-vers-vidéo sur HiAPI : tutoriel curl et Python
Démonstration pratique axée sur la requête : construire l'appel du prompt au clip vidéo, soumettre la requête, interroger l'état d'achèvement et télécharger le résultat