HiAPI
Blog

Tutorial

So verwendest du die Ray 3.2 Text-zu-Video-API: curl, Python und eine direkt ausführbare Anfrage

Oct 20, 2026
So verwendest du die Ray 3.2 Text-zu-Video-API: curl, Python und eine direkt ausführbare Anfrage

Ray 3.2 ist ein Text-zu-Video-Modell im hiapi-Modellkatalog und wird wie alle anderen Videomodelle über eine einheitliche asynchrone Task-API aufgerufen – die Modell-ID lautet ray-3.2/text-to-video und wird an POST /v1/tasks gesendet. Im Gegensatz zu manchen Videomodellen, deren einziger Anpassungsparameter der Prompt ist, bietet Ray 3.2 drei wirklich nutzbare Ausgabesteuerungen – duration, resolution und aspect_ratio – und jede davon wird serverseitig streng validiert.

Dieser Leitfaden ermöglicht es dir, auf Anhieb eine erfolgreiche Anfrage zu senden: das exakte Eingabe-Schema (am 2026-10-19 gegen die Live-API verifiziert), einen direkt kopierbaren curl-Aufruf, ein vollständiges Python-Skript zum Senden/Abfragen/Herunterladen sowie Produktionsdetails – Callbacks, idempotente Wiederholungsversuche und die Fehlerantworten, die du tatsächlich sehen wirst.

Was du baust und was du vorbereiten musst

Ziel: Einen Text-Prompt senden, die Task abfragen und einen stummen .mp4-Clip (5 oder 10 Sekunden) herunterladen.

Voraussetzungen:

  • Ein hiapi-API-Schlüssel – erhältlich in deiner Konsole. Der Schlüssel hat die Form sk-... und wird im Authorization: Bearer-Header übergeben. Neu bei der Task-API? Beginne mit dem Quickstart.
  • Ein beliebiger HTTP-Client. Wir zeigen curl und Python (requests).

Die Ausgabe von Ray 3.2 wird pro Clip abgerechnet, und der Preis steigt je nach deinen Einstellungen deutlich – die aktuellen Tarife findest du auf der Preisseite. Beginne beim Iterieren an Prompts mit 540p / 5 Sekunden; ein 1080p-Clip von 10 Sekunden kann um ein Vielfaches teurer sein als eine budgetgerechte Bildgenerierung, also lass deine Entwicklungsschleife nicht dauerhaft auf den höchsten Einstellungen laufen.

Das exakte Eingabe-Schema (ein Pflichtfeld, drei strikte Enums)

Alles liegt in einem input-Objekt. Feld für Feld gegen die Live-API verifiziert:

Feld Typ Pflicht Erlaubte Werte Standardwert
prompt string Ja Szenenbeschreibung, maximal 6000 Zeichen —
duration integer Nein 5 oder 10 5
resolution string Nein 540p, 720p, 1080p 540p
aspect_ratio string Nein 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 16:9

Drei Dinge solltest du dir vor dem Schreiben von Code merken:

  1. duration ist ein Integer, kein String. Sende eine nackte Zahl – "duration": 5. Das ist das Gegenteil einiger anderer Video-Modelle der Task-API (zum Beispiel verlangt hailuo-2.3 "duration": "6" als String). Wenn du einen Request-Body von einem Modell auf ein anderes überträgst, prüfe dieses Feld erneut; es ist der häufigste modellübergreifende Fehler.
  2. Enum-Werte werden validiert, nicht abgeschnitten. Werte außerhalb des Bereichs werden mit 400 abgelehnt statt stillschweigend gerundet. Es gibt kein 2k, kein 480p, kein 2:1.
  3. Kein prompt_optimizer, seed oder negative_prompt. Die Komposition wird ausschließlich über aspect_ratio plus Prompt gesteuert. Wenn du Felder sendest, die das Schema nicht kennt, erwarte einen 400 – das Eingabe-Schema von /v1/tasks unterscheidet sich je nach Modell, also gehe nicht davon aus, dass anderswo gültige Schlüssel hier übernommen werden.

Was die Validierung tatsächlich zurückgibt

Hier sind echte Antworten des Live-Endpunkts (absichtlich ungültige Werte gesendet, keine Task erstellt, keine Abrechnung):

// 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 nennt das exakte Feld und die exakt erlaubte Menge – wenn du also einen Enum-Wert vergessen hast, sagt dir die API Bescheid. Beachte, dass 5, 10 bei duration ohne Anführungszeichen stehen (Zahlen), während '540p' bei resolution ein String mit Anführungszeichen ist: Dieser Anführungszeichen-Unterschied erinnert dich daran, welches Feld ein Integer ist.

Minimales lauffähiges Beispiel: curl

Task erstellen:

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": "In einer regnerischen Nacht wirbelt eine Straßentänzerin unter Neonlicht, Pfützen spiegeln pinkes und blaues Licht wider, ihre Jacke flattert beim Drehen, die Kamera umkreist sie in niedriger Perspektive, filmisch",
      "duration": 5,
      "resolution": "540p",
      "aspect_ratio": "9:16"
    }
  }'

Die Erstellungsantwort enthält eine Task-ID (gekürzt):

{ "data": { "taskId": "task_01k..." } }

Frage sie ab, bis sie einen Endzustand erreicht:

curl -s https://api.hiapi.ai/v1/tasks/task_01k... \
  -H "Authorization: Bearer sk-YOUR_KEY"

Während die Task läuft, meldet data.status einen laufenden Status. Die beiden Endzustände sind success und fail. Bei Erfolg (gekürzt):

{
  "data": {
    "taskId": "task_01k...",
    "status": "success",
    "output": [ { "url": "https://.../clip.mp4" } ]
  }
}

Lade data.output[0].url sofort herunter. Ausgabe-URLs sind signiert und laufen ab – speichere die Bytes in deinem eigenen Storage, statt die Task-URL direkt zu hotlinken. Ray 3.2 liefert stumme MP4s (keine Tonspur), also warte nicht auf einen Audiostream, der nie kommt.

Vollständiges Python-Skript (Senden → Abfragen → Herunterladen)

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(
    "Ein Papierboot treibt einen regengefüllten Abfluss hinunter, Wassertropfen ziehen "
    "Kreise auf der Oberfläche, Herbstblätter wirbeln vorbei, Kamera dicht über dem "
    "Wasser in niedriger Position, weiches bedecktes Licht"
)
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)")

Installiere die Abhängigkeit mit pip install requests, setze deinen Schlüssel ein, und wenn die Task fertig ist, liegt eine .mp4 auf der Festplatte. Video-Tasks dauern Minuten, nicht Sekunden – gib deiner Abfrageschleife eine großzügige Frist (oben 15 Minuten), statt anzunehmen, dass sie schnell zurückkehrt.

Hinweise für die Produktion: Callbacks, Idempotenz, Fehler

Bevorzuge Callbacks gegenüber Polling

Für alles außer Skripten registriere beim Erstellen der Task einen Webhook, statt zu pollen:

{
  "model": "ray-3.2/text-to-video",
  "input": { "prompt": "...", "duration": 10, "resolution": "720p" },
  "callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}

Mit "when": "final" ruft hiapi deinen Endpunkt einmal auf, sobald die Task einen Endzustand erreicht – kein Polling-Traffic und keine zwischen zwei Intervallen verpasste Fertigstellungsbenachrichtigung. Dein Handler führt dann GET /v1/tasks/<id> aus (oder liest den gelieferten Response-Body), um output[0].url zu erhalten. Für CLIs und Notebooks, die keinen HTTPS-Endpunkt bereitstellen können, bleibt Polling in Ordnung.

Halte Wiederholungsversuche idempotent

Persistiere die taskId in dem Moment, in dem der Erstellungsaufruf zurückkehrt. Wenn dein Prozess mitten in der Generierung abstürzt, stelle den Zustand durch Abfragen der gespeicherten ID wieder her – erstelle die Task nicht neu, sonst zahlst du für eine zweite Renderung. Erstelle nur dann neu, wenn die ursprüngliche Erstellungsanfrage selbst fehlgeschlagen ist, bevor sie eine Task-ID zurückgab. Da Ray 3.2 pro Clip abrechnet und Clips in hoher Auflösung nicht billig sind, ist doppeltes Erstellen ein echter Kostenfehler, nicht nur Zeitverschwendung.

Fehler, die du tatsächlich sehen wirst

Jede der folgenden Zeilen ist eine verifizierte Live-Antwortform:

Symptom Antwort Behebung
Schlüssel fehlt/ungültig 401, verschachtelt {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} Prüfe den Authorization: Bearer sk-...-Header und ob der Schlüssel Zugriff hat. Gib die request_id an, wenn du den Support kontaktierst.
Falscher Enum-Wert 400 INVALID_REQUEST, flach {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} Lies das in message genannte Feld; es listet die exakt erlaubte Menge auf.
duration als String gesendet 400 INVALID_REQUEST Sende eine nackte Integer-Zahl 5 oder 10, nicht "5".
Unbekannte Modell-ID 400, error_code: "MODEL_UNAVAILABLE", "model not available via /v1/tasks" Verwende strikt ray-3.2/text-to-video – die kanonische ID findest du auf der Modellseite.
Falsche Task-ID beim Abfragen 404, flach {"code":404,"data":null,"message":"task not found"} (Achtung: bei 404 gibt es kein error_code) Die ID ist falsch, oder du hast mit dem Schlüssel eines anderen Kontos abgefragt.
status: "fail" beim Abfragen Endzustand der Task, Details in data.error Lies data.error.code / data.error.message. Fehlgeschlagene Tasks werden erstattet; Inhaltsrichtlinien-Verstöße und Upstream-Kapazitätsprobleme zeigen sich hier – versuche es bei Inhaltsmarkierungen mit einem umformulierten Prompt erneut.

Verwandte Ressourcen

Häufig gestellte Fragen

Wie lautet die Modell-ID, und welchen Endpunkt sollte ich aufrufen? ray-3.2/text-to-video, als oberstes model an POST https://api.hiapi.ai/v1/tasks gesendet, mit den Parametern unter input. Es ist asynchron – du erhältst eine taskId und fragst dann GET /v1/tasks/<id> ab (oder registrierst einen Callback).

Wird duration in Sekunden angegeben, und warum schlägt "5" fehl? Clips sind 5 oder 10 Sekunden lang, und das Feld ist ein Integer: Sende 5 oder 10. Ein String mit Anführungszeichen oder eine beliebige andere Zahl wie 7 schlägt fehl mit 400 INVALID_REQUEST: duration: value must be one of 5, 10.

Kann ich Auflösung und Seitenverhältnis festlegen? Ja – genau darin unterscheidet sich Ray 3.2 von reinen Prompt-basierten Videomodellen. resolution ist 540p, 720p oder 1080p; aspect_ratio ist eines von 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Beide sind optional (Standard 540p und 16:9) und lehnen Werte außerhalb des Bereichs mit 400 ab.

Was kostet ein Clip? Ray 3.2 rechnet pro Clip ab, wobei die Auflösung der größte Hebel ist – bei gleicher Länge kostet ein 1080p-Clip ein Vielfaches eines 540p-Clips, und ein 10-Sekunden-Clip kostet etwa dreimal so viel wie ein 5-Sekunden-Clip. Die Tarife ändern sich, also sieh auf der Preisseite nach, statt eine Zahl hart zu kodieren, und prototype mit 540p/5 Sekunden.

Haben die Clips Audio? Nein – Ray 3.2 Text-zu-Video liefert stumme MP4s. Wenn du Ton brauchst, füge ihn nachträglich hinzu oder verwende ein separates Audiomodell.

Unterstützt Ray 3.2 Image-zu-Video? Ja, als separate Modell-ID auf derselben Task-API: ray-3.2/image-to-video. Ihr Eingabe-Schema unterscheidet sich (sie nimmt ein Referenzbild entgegen), also probe es aus, bevor du diesen Request-Body wiederverwendest – siehe Image-zu-Video-Modellseite.

Meine Generierung ist langsam oder scheint zu hängen. Was ist normal? Video-Tasks laufen mehrere Minuten. Behalte in deiner Abfrageschleife die nicht-terminalen data.status bei und warte – rechne mit einer Frist von 10–15 Minuten, oder verwende einen callback mit "when": "final", damit hiapi dich im Endzustand benachrichtigt, statt dass du selbst ein Intervall schätzt.

Ähnliche Artikel

Alle Artikel ansehen →

Starte mit persistenten KI-Artefakten

Hol dir deinen API-Key und rufe Bild-, Video- und Audiomodelle über eine einzige task-basierte API auf.

API-Dokumentation lesen