HiAPI
Blog

Tutorial

PixVerse V6 Text-zu-Video-API: Ein curl- und Python-Beispiel, das tatsächlich funktioniert

Oct 20, 2026
PixVerse V6 Text-zu-Video-API: Ein curl- und Python-Beispiel, das tatsächlich funktioniert
Modell
pixverse-v6

Mit pixverse-v6/text-to-video auf hiapi ein Video zu erzeugen, ist im Kern ein POST /v1/tasks plus eine Runde Polling – exakt dasselbe asynchrone Aufgabenmuster, das jedes generative Modell auf der Plattform verwendet. Dieser Artikel liefert dir direkt kopierbare curl- und Python-Beispiele, die Eingabefelder, die der Endpoint tatsächlich validiert, sowie den Aufgaben-Lebenszyklus und die Stolperfallen, die ich bei einem tatsächlich durchgeführten Generierungslauf festgehalten habe.

Was du vor dem Start brauchst

  • Einen hiapi API-Key. Erstelle ihn im Dashboard und übergib ihn per Header Authorization: Bearer sk-<dein key>. Das Header-Format findest du in der Authentifizierungsdokumentation.
  • Die model id lautet pixverse-v6/text-to-video. Behalte den Schrägstrich in der Mitte bei – er gehört zur id und ist kein URL-Pfad.
  • curl benötigt keine Installation; das Python-Beispiel verwendet nur die Standardbibliothek plus requests.

PixVerse V6 Text-zu-Video verwandelt einen Text-Prompt in einen 1–15 Sekunden langen Videoclip mit 360p–1080p. Es nutzt die einheitliche asynchrone Aufgaben-API: Aufgabe einreichen → Ergebnis pollen → das Video herunterladen, bevor die Ausgabe-URL abläuft.

Minimaler lauffähiger Request (curl)

Reiche die Aufgabe bei POST /v1/tasks ein:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<dein key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "pixverse-v6/text-to-video",
    "input": {
      "prompt": "Am Morgen im Sonnenlicht trottet ein roter Fuchs durch frisch gefallenen Schnee, filmische Optik, Zeitlupe",
      "aspect_ratio": "16:9",
      "duration": 5,
      "resolution": "720p"
    }
  }'

In der Antwort erhältst du eine Aufgaben-id:

{ "code": 200, "data": { "taskId": "tk-hiapi-...." }, "message": "success" }

Dann pollst du GET /v1/tasks/<taskId>, bis data.status zu success wird:

curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-.... \
  -H "Authorization: Bearer sk-<dein key>"

Nach Erfolg steht die URL des fertigen Videos in data.output[0].url:

{
  "code": 200,
  "data": {
    "status": "success",
    "storage": "temp",
    "output": [
      { "type": "video", "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1793036664 }
    ]
  },
  "message": "success"
}

Diese Ausgabe-URL ist temporär – sie enthält einen expireAt-Zeitstempel (gemessen: 7 Tage nach der Generierung). Lade die .mp4 sofort herunter und speichere sie in deinem eigenen Objektspeicher; verlinke diese Adresse nicht direkt per Hotlink.

Derselbe Ablauf (Python)

import time, requests

BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<dein key>", "Content-Type": "application/json"}

def create_task():
    payload = {
        "model": "pixverse-v6/text-to-video",
        "input": {
            "prompt": "Am Morgen im Sonnenlicht trottet ein roter Fuchs durch frisch gefallenen Schnee, filmische Optik, Zeitlupe",
            "aspect_ratio": "16:9",
            "duration": 5,
            "resolution": "720p",
        },
    }
    r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
    r.raise_for_status()
    data = r.json()
    task_id = (data.get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"Erstellung fehlgeschlagen: {data}")
    return task_id

def wait_for(task_id, timeout_s=600):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        try:
            r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
            task = (r.json().get("data") or {})
        except requests.RequestException:
            time.sleep(5)          # ein einzelner Netzwerk-Aussetzer sollte nicht das gesamte Polling abbrechen
            continue
        status = task.get("status")
        if status == "success":
            return task["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"Aufgabe fehlgeschlagen: {task.get('error')}")
        time.sleep(5)              # noch in der Warteschlange/in der Wiedergabe – mit derselben task_id weiter pollen
    raise TimeoutError(task_id)

task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("out.mp4 gespeichert")

Die Polling-Schleife prüft nur die beiden Endzustände success und fail; bei allen anderen Status wartet sie einfach weiter – so kann der Code weder handling noch archiving während der Wiedergabe fälschlich interpretieren. Entscheidend: Wenn ein einzelner Polling-Request selbst fehlschlägt, warte kurz und frage mit derselben gespeicherten task_id erneut ab, statt die Aufgabe neu einzureichen – eine erneute Einreichung rendert noch einmal und berechnet noch einmal.

Die Parameter, die pixverse-v6/text-to-video tatsächlich validiert

Die folgenden Felder akzeptiert der Endpoint tatsächlich. Jedes davon habe ich bestätigt, indem ich einen ungültigen Wert gesendet und die eigene Validierungsfehlermeldung zurückgelesen habe, und mit der Modell-Dokumentation abgeglichen:

Feld Typ Wert / Bereich Standardwert Beschreibung
prompt string 1–2048 Bytes UTF-8 (1 chinesisches Zeichen = 3 Bytes, ca. 682 Zeichen) — Pflichtfeld.
aspect_ratio enum 16:9, 4:3, 1:1, 3:4, 9:16, 2:3, 3:2, 21:9 16:9 Beachte, dass 21:9 (Ultrabreit) sowie 2:3/3:2 unterstützt werden.
duration integer 1–15 5 Einheit Sekunden, muss eine Ganzzahl sein, kein String.
resolution enum 360p, 540p, 720p, 1080p 720p Ausgabeauflösung.
generate_audio boolean true / false false Ob Hintergrundmusik, Soundeffekte und Dialog gleichzeitig generiert werden; standardmäßig aus, für Audio musst du es explizit aktivieren.
negative_prompt string maximal 2048 Bytes UTF-8 — Optional; Inhalte, die du vermeiden möchtest.
seed integer beliebige Ganzzahl — Optional; gleicher seed + gleicher prompt reproduziert dasselbe Ergebnis.
style enum anime, 3d_animation, clay, comic, cyberpunk keiner Optionales Stil-Preset; leer lassen für natürlichen Look.

Wenn du statt Polling einen Callback verwenden willst, kannst du auf derselben Ebene wie input ein callback-Objekt mitgeben: url (HTTPS-Callback-Adresse) + when (derzeit nur final, also Callback beim Endzustand der Aufgabe).

So schreibst du es für die Produktion

  • Das ist ein geschlossenes Schema. Jedes Feld, das nicht in der obigen Tabelle steht, wird direkt abgelehnt mit invalid input: <root>: additional properties '<Feld>' not allowed. Das ist tatsächlich gut: Vertippte oder erfundene Felder schlagen schon beim Einreichen deutlich fehl, statt still ignoriert zu werden.
  • duration ist eine Ganzzahl – anders als bei manchen Videomodellen der Plattform, die Strings ("6") akzeptieren. Sendest du "5", erhältst du invalid input: duration: got string, want integer; bei Ausreißern werden dir direkt die Grenzen genannt, z. B. duration: maximum: got 999, want 15, duration: minimum: got 0, want 1.
  • Fehler melden jeweils nur ein Feld, der Envelope ist flach: {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}. Korrigiere das gemeldete Feld und sende erneut; das nächste ungültige Feld (falls vorhanden) taucht beim nächsten Aufruf auf.
  • Bei einer fehlgeschlagenen Aufgabe ist HTTP trotzdem 200. Die Fehlerinformation steht in data.status: "fail" des Antwortkörpers; zu prüfen ist dieses status-Feld, nicht der HTTP-Statuscode.
  • Polling oder Callback? Für leichte Skripte ist Polling am einfachsten; für Skalierung, bei der du keine Verbindung dauerhaft offen halten willst, nutze callback. In beiden Fällen musst du output[0].url sofort herunterladen – die URL enthält expireAt und wird nach Ablauf zu 404.

Messprotokoll: Ich habe es tatsächlich einmal ausgeführt

Dieser Artikel basiert nicht nur auf Read-only-Sonden – ich habe mit einer echten Anfrage den vollständigen Lebenszyklus durchlaufen und dokumentiere es hier:

  • Erstellung: Der obige Request mit 720p / 5 Sekunden / 16:9 wurde abgeschickt und lieferte sofort {"code":200,"data":{"taskId":"tk-hiapi-01M5AM..."},"message":"success"}. Beachte, dass die taskId ein String mit Präfix tk-hiapi- ist, keine UUID.
  • Polling: data.status von GET /v1/tasks/<id> durchlief nacheinander handling → archiving → success; der gesamte 5-Sekunden-Clip brauchte von der Erstellung bis zur Fertigstellung etwa 74 Sekunden.
  • Ausgabe: Im Endzustand ist data.output[0] gleich {"type":"video","url":"https://temp.hiapi.ai/....mp4","expireAt":...,"artifactId":"...","storage":"temp"}. expireAt minus Erstellungszeit ergibt genau 604800 Sekunden, also 7 Tage.
  • Artefakt: Ein HEAD auf diese Ausgabe-URL lieferte content-type: video/mp4 und eine Größe von etwa 2,2 MB – bestätigt eine gültige mp4-Datei.

Eine Korrektur zum Thema Audio ist es wert, separat festgehalten zu werden: Ich habe benachbarte Feldnamen jeweils mit ungültigen Werten geprüft – generate_audio meldete got string, want boolean (also ist es ein gültiges boolesches Feld), während sound und audio beide additional properties not allowed meldeten (existieren nicht). Das heißt: Audio wird über den Schalter generate_audio gesteuert, Standard false; auf der Preisseite gibt es entsprechend zwei Stufen „Sound On / Sound Off“. In diesem Test habe ich generate_audio nicht aktiviert, daher war das Ergebnis ein stummer Clip.

Zur Bildqualität habe ich keine subjektive Bewertung abgegeben (in diesem Test habe ich nur den Request-Vertrag, den Aufgaben-Lebenszyklus und die Gültigkeit der mp4-Ausgabe verifiziert) – diesen Teil beurteile bitte selbst, nachdem du mit deinen eigenen Prompts tatsächlich generiert hast.

Wie die Kosten berechnet werden

pixverse-v6/text-to-video wird pro Sekunde abgerechnet (der Abrechnungsfaktor ist duration); je länger die Dauer, desto teurer; je höher die Auflösung und wenn generate_audio aktiviert ist (Stufe „Sound On“), desto höher der Sekundenpreis. Die konkreten Sekundensätze richten sich nach den Echtzeitdaten auf der Preisseite – wirf einen Blick darauf, bevor du in großem Umfang generierst.

Relevante Links

Häufige Fragen

Ist duration in Sekunden oder Frames? Sekunden – eine beliebige Ganzzahl zwischen 1 und 15, Standard 5.

Kann man Videos mit Ton generieren? Ja. Setze generate_audio auf true, dann generiert das Modell Hintergrundmusik, Soundeffekte und Dialog mit; Standard ist false (stumm). Das Aktivieren von Audio nutzt eine teurere Abrechnungsstufe, Details auf der Preisseite.

Wie lang darf der Prompt sein? Die Obergrenze liegt bei 2048 Bytes UTF-8. Ein chinesisches Zeichen zählt als 3 Bytes, also maximal etwa 682 chinesische Zeichen.

Worin unterscheidet es sich von Bild-zu-Video? Dieser Endpoint (pixverse-v6/text-to-video) startet nur von einem Text-Prompt. Bild-zu-Video ist eine andere model id, die ein Ausgangsbild entgegennimmt und es in Bewegung setzt – wenn du ein vorhandenes Bild animieren statt aus dem Nichts generieren willst, nutze jene.

Warum meldet mein Request "additional properties not allowed"? Du hast ein Feld übergeben, das nicht im Schema ist. Die Eingabe akzeptiert nur prompt, aspect_ratio, duration, resolution, generate_audio, negative_prompt, seed und style.

Ä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