Tutorial
So verwendest du die hailuo 2.3 Fast Image-to-Video API: curl, Python und ein lauffähiger Request
Du hast ein statisches Bild und möchtest daraus ein kurzes Video machen. Diese Anleitung zeigt dir den Zugang zu hailuo-2.3-fast/image-to-video über die hiapi Task-API: das exakte Eingabe-Schema (geprüft gegen den Live-Validator), einen direkt kopierbaren curl-Request, ein vollständiges Python-Skript, das bis zur Fertigstellung pollt, sowie Details für den Produktivbetrieb – Callbacks, idempotente Wiederholungsversuche und die Fehlerantworten, auf die du tatsächlich stoßen wirst.
Was du vorbereiten musst
- Einen hiapi API-Schlüssel – erhältlich in deiner Konsole. Der Schlüssel hat die Form
sk-...und wird imAuthorization: Bearer-Header übergeben. - Ein Quellbild, das unter einer öffentlich erreichbaren HTTPS-URL gehostet wird. Die API erwartet eine URL, keine hochgeladene Datei.
- Einen beliebigen HTTP-Client. Die folgenden Beispiele verwenden curl und Pythons
requests.
Die sekundengenaue Preisgestaltung des Modells findest du auf der Preisseite.
Eingabe-Schema (verifiziert)
hailuo-2.3-fast/image-to-video verwendet den einheitlichen asynchronen Task-Endpunkt: POST /v1/tasks legt einen Task an, GET /v1/tasks/<taskId> fragt den Task ab. Das Eingabe-Schema ist streng – unbekannte Felder werden mit 400 abgelehnt, statt stillschweigend ignoriert zu werden.
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
prompt |
string | ✅ | Beschreibt die gewünschte Bewegung |
image_url |
string | ✅ | Singularform – ein URL-String, kein image_urls-Array |
duration |
string | optional | "6" oder "10" – eine Zeichenkette, keine Zahl |
prompt_optimizer |
boolean | optional | Lässt das Backend deinen Prompt für die Bewegung umschreiben |
Der Validator fängt drei typische Stolperfallen ab:
durationmuss ein String sein. Wenn du"duration": 6sendest, erhältst du400mit dem Hinweisduration: got number, want string. Sende stattdessen"duration": "6".- Das Feld heißt in der Singularform
image_url. Viele andere Videomodelle auf der Plattform (Grok Imagine, Kling) erwarten einimage_urls-Array. Dieses Modell erwartet einen einzelnen String. - Es gibt kein
resolution,aspect_ratio,seed,watermarkoderend_image_url. Sie alle liefernadditional properties ... not allowed. Das Ausgabeformat folgt deinem Quellbild; die Bewegung lässt sich nur über den Prompt steuern.
Minimaler lauffähiger Request: curl
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "hailuo-2.3-fast/image-to-video",
"input": {
"prompt": "Die Kamera fährt langsam vorwärts, Dampf steigt von der Kaffeetasse auf, sanftes Morgenlicht",
"image_url": "https://your-cdn.example.com/coffee.jpg",
"duration": "6"
}
}'
Erfolgreiche Antwort:
{
"code": 200,
"data": { "taskId": "tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V" },
"message": "success"
}
Anschließend pollen:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V \
-H "Authorization: Bearer sk-YOUR_KEY"
Während das Video gerendert wird, ist data.status gleich "handling":
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01KX4W3SVW8S8EHD5VX45JH95V",
"model": "hailuo-2.3-fast/image-to-video",
"status": "handling",
"storage": "temp",
"completed": 0,
"created": 1783648872
},
"message": "success"
}
Die Endzustände sind "success" (Video-URL in data.output[0].url) und "fail" (Details in data.error).
Vollständiges Python-Skript
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"] # sk-...
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def create_task(prompt: str, image_url: str, duration: str = "6") -> str:
resp = requests.post(
API_BASE,
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "hailuo-2.3-fast/image-to-video",
"input": {
"prompt": prompt,
"image_url": image_url,
"duration": duration, # String: "6" oder "10"
},
},
timeout=60,
)
body = resp.json()
if resp.status_code != 200 or not body.get("data", {}).get("taskId"):
raise RuntimeError(f"create failed: {resp.status_code} {body}")
return body["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
task = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
status = task.get("status")
if status == "success":
return task
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} still running after {timeout_s}s")
if __name__ == "__main__":
task_id = create_task(
prompt="Die Katze blinzelt, dreht den Kopf zum Fenster, eine Brise streicht über ihr Fell",
image_url="https://your-cdn.example.com/cat.jpg",
duration="6",
)
print("task:", task_id)
task = wait_task(task_id)
video_url = task["output"][0]["url"]
print("video:", video_url)
# Die URL liegt im temporären Speicher mit Ablaufzeit – lade sie sofort herunter und verlinke sie nicht direkt.
mp4 = requests.get(video_url, timeout=120).content
with open("output.mp4", "wb") as f:
f.write(mp4)
print(f"saved output.mp4 ({len(mp4)} bytes)")
Dieses Skript macht zwei Dinge richtig, die schnell zusammengeschusterte Lösungen oft übersehen:
- Es lädt das Video sofort herunter.
storage: "temp"bedeutet, dass die Ausgabe-URL eine Ablaufzeit (expireAt) hat. Persistiere die Bytes in deinem eigenen Speicher; speichere die zurückgegebene URL niemals in deiner Datenbank. - Es behandelt
failals Endzustand. Ein erneutes Pollen eines fehlgeschlagenen Tasks belebt ihn nicht wieder – lege einen neuen Task an.
Hinweise für den Produktivbetrieb
Callbacks statt Polling verwenden
Für Anwendungsfälle außerhalb von Skripten registriere beim Anlegen des Tasks einen Webhook und überspringe die Polling-Schleife komplett:
{
"model": "hailuo-2.3-fast/image-to-video",
"input": { "prompt": "...", "image_url": "https://...", "duration": "6" },
"callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}
Mit "when": "final" wird dein Endpunkt einmal aufgerufen, wenn der Task success oder fail erreicht. Faustregel: Polling eignet sich für CLIs, Batch-Jobs und alle temporären Szenarien; sobald du einen Server hast, der bereits lauscht, ist ein Callback überlegen – Videotasks laufen mehrere Minuten, und eine Polling-Schleife ist in diesen Minuten ein belegter Verbindungsslot und ein verschwendeter Worker.
Idempotenz
Der Create-Aufruf selbst ist nicht idempotent – jedes POST /v1/tasks, das die Validierung besteht, legt einen neuen (kostenpflichtigen) Task an. Wenn dein Task-Runner bei einem Timeout erneut versucht, speichere die erhaltene taskId vor der Verarbeitung des Ergebnisses, verschlüsselt mit deiner eigenen Request-ID. Wenn bei einem Wiederholungsversuch für diesen Schlüssel bereits eine taskId existiert, pollst du sie, statt einen doppelten Task anzulegen.
Fehler, auf die du tatsächlich stoßen wirst
| Symptom | Bedeutung | Behebung |
|---|---|---|
401 — {"error":{"code":"permission_denied","type":"hiapi_error"}} |
Der Schlüssel ist ungültig, oder er darf dieses Modell nicht verwenden | Prüfe den Schlüssel in der Konsole; die Antwort enthält eine request_id für den Support |
400 INVALID_REQUEST — duration: got number, want string |
Es wurde eine JSON-Zahl statt eines Strings verwendet | "duration": "6" |
400 INVALID_REQUEST — additional properties '...' not allowed |
Du hast ein Feld außerhalb des Schemas gesendet | Entferne es – die Meldung benennt jedes fehlerhafte Feld |
400 INVALID_REQUEST — missing required field "prompt" / "image_url" |
Die Eingabe ist leer oder der Feldname ist falsch | Beide Felder sind erforderlich |
Der Task erreicht nach dem Anlegen fail |
Laufzeitfehler – häufige Ursache ist eine Bild-URL, die das Backend nicht abrufen kann | Der Validator ruft dein Bild beim Anlegen nicht ab; stelle sicher, dass die URL öffentlich erreichbar ist |
Die letzte Zeile verdient besondere Betonung: Die Validierung beim Anlegen betrifft nur das Schema. Eine falsch geschriebene oder private image_url liefert dir eine scheinbar normale taskId und einen Task, der nach einigen Minuten stirbt – alarmiere daher bei fail, nicht nur bei HTTP-Fehlern.
Weiterführende Lektüre
- Modellseite hailuo-2.3-fast/image-to-video — Playground und sekundengenaue Preisgestaltung
- Image-to-Video-API-Workflow: Der Produktionsleitfaden — Architektur für Batch-Verarbeitung, Speicherung und Wiederholungsversuche rund um i2v-Endpunkte
- Text-to-Video vs. Image-to-Video API — Wann du die Generierung an einem Quellbild verankern solltest
- Kling Image-to-Video API-Leitfaden — dieselbe Task-API, ein anderes Eingabe-Schema, ein nützlicher Vergleich
Häufig gestellte Fragen
Kann ich Auflösung oder Seitenverhältnis festlegen?
Nein. Das Schema von hailuo-2.3-fast/image-to-video lehnt resolution und aspect_ratio als unbekannte Felder ab. Das Ausgabeformat folgt deinem Quellbild; wenn du ein bestimmtes Seitenverhältnis brauchst, schneide das Eingabebild vorher zu.
Welche Dauern werden unterstützt?
Genau zwei: "6" und "10" Sekunden, übergeben als String. Jeder andere Wert liefert 400 mit dem Hinweis value must be one of '6', '10'.
Kann ich mehrere Referenzbilder übergeben?
Nein – das Feld ist ein einzelner image_url-String. Modelle, die Bild-Arrays akzeptieren (etwa image_urls bei Grok Imagine), verwenden ein anderes Schema; kopiere Request-Bodies nicht ungeprüft zwischen Modellen hin und her.
Wie steuere ich die Bewegung?
Nur über den prompt – es gibt keine Parameter für Bewegungsintensität oder Kameraführung. Beschreibe die Bewegung explizit („Die Kamera fährt langsam vorwärts“, „Das Haar weht im Wind“). Optional kannst du "prompt_optimizer": true setzen, damit das Backend deinen Prompt erweitert.
Gibt es eine langsamere Variante mit höherer Qualität?
Ja – hailuo-2.3/image-to-video (ohne -fast) ist ebenfalls auf der Plattform verfügbar, und hailuo-2.3/text-to-video deckt Szenarien ohne Quellbild ab. Prüfe vor dem Wechsel das Schema jeder Variante; die Eingabefelder sind nicht garantiert identisch.
Was kostet es? Die Abrechnung erfolgt nach Sekunden des generierten Videos und variiert je nach Modell; die aktuellen Sätze findest du auf der Preisseite.
Brauche ich zum Ausprobieren einen API-Schlüssel?
Ja – alle Task-API-Aufrufe erfordern einen Bearer sk-...-Schlüssel. Du kannst einen in der Konsole anlegen und zuerst im Playground auf der Modellseite testen.
Ähnliche Artikel
Alle Artikel ansehen →-
Tutorial
So rufen Sie hailuo-2.3-fast/image-to-video über die HiAPI API auf: curl und Python in der Praxis
Die erste lauffähige Anfrage für die schnelle, kostengünstige Bild-zu-Video-Stufe – von der Modell-ID bis zum heruntergeladenen MP4
-
Tutorial
So rufen Sie hailuo-2.3/text-to-video über die HiAPI API auf: curl, Python und lauffähige Anfragebeispiele
-
Tutorial
Kandinsky 6.0 Pro Text-zu-Video auf HiAPI: curl- und Python-Tutorial
Eine anfrageorientierte praktische Demonstration: Aufbau des Aufrufs vom Prompt zum Videoclip, Absenden der Anfrage, Abfragen des Fertigstellungsstatus und Herunterladen des Ergebnisses