HiAPI
Blog

Tutoriel

Comment utiliser l'API Ray 3.2 text-to-video : curl, Python et une requête directement exécutable

Oct 20, 2026
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ête Authorization: Bearer. Vous découvrez l'API de tâches ? Commencez par le guide de démarrage rapide.
  • N'importe quel client HTTP. Nous montrerons curl et 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 :

  1. duration est 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.
  2. 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 de 2k, pas de 480p, pas de 2:1.
  3. Pas de prompt_optimizer, seed ni negative_prompt. La composition se contrôle entièrement via aspect_ratio et 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/tasks varie 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

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 →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API