HiAPI
Blog

Tutorial

vidu-q3-ad reference-to-video API: curl, Python und eine lauffähige Anfrage

Oct 20, 2026
vidu-q3-ad reference-to-video API: curl, Python und eine lauffähige Anfrage

Was du baust

Starte einen reference-to-video-Aufruf auf der asynchronen /v1/tasks-API von hiapi, um aus 1–7 Produktstandbildern einen kurzen Video-Werbespot mit nativem Audio zu machen. vidu-q3-ad/reference-to-video ist die werbeorientierte Stufe von Vidu Q3: Du lädst Produktreferenzbilder hoch, schreibst eine Kamerabeschreibung, und das Modell liefert ein 3–15-sekündiges MP4 zurück – mit intelligentem Schnitt, Kamerabewegung und generierten Soundeffekten. Es gibt keine separate Tonspur, die du bereitstellen musst.

Du sendest ein einziges POST ab, pollst dann (oder empfängst einen Callback), bis die Aufgabe abgeschlossen ist, und lädst anschließend das MP4 herunter. Hole dir zuerst einen Schlüssel aus der hiapi-Konsole; jede Anfrage unten verwendet Authorization: Bearer sk-....

Drei Dinge, die du wörtlich übernehmen musst:

  • Submit-Endpunkt: POST https://api.hiapi.ai/v1/tasks
  • Polling-Endpunkt: GET https://api.hiapi.ai/v1/tasks/{taskId}
  • Modell-ID: vidu-q3-ad/reference-to-video – weder der Schrägstrich noch das Suffix -ad dürfen fehlen; vidu-q3-mix und vidu-q4-preview sind andere Endpunkte.

Eingabe-Schema (durch Live-Probing ermittelt)

Feld Pflichtfeld Typ Beschreibung
prompt Ja string Kamerabeschreibung; verweise per Nummer auf Produkte, z. B. „die Uhr aus Referenzbild 1“
reference_image_urls Ja array, 1–7 Öffentliche URLs der Produktstandbilder (serverseitig abgerufen)
duration Ja integer, 3–15 Sekunden; muss eine ganze Zahl sein (4.5 wird abgelehnt)
size Nein enum (10 Werte) Bestimmt gleichzeitig das Seitenverhältnis und die 720/1080-Stufe; Standard ist 1280*720

Der Validator ist sehr streng – jedes Feld außerhalb der obigen Liste wird direkt abgelehnt. Zwei Arten von Ablehnungen sind besonders erwähnenswert, weil sie alle erwischen, die von anderen hiapi-Videomodellen migrieren:

  • aspect_ratio und resolution werden beide abgelehnt. Fast alle anderen hiapi-Videoendpunkte verwenden diese beiden Felder; q3-ad nicht. Die Größe wird ausschließlich über size gesteuert.
  • reference_audio_urls wird ebenfalls abgelehnt. Anders als die reference-to-video-Stufe von Vidu Q4 (die Sprachclips akzeptiert) hat q3-ad keinen Audioeingang – seine Tonspur wird nativ generiert. (Wie ich das bestätigt habe, steht im Verifikationsabschnitt unten.)

Wie man size wählt

size ist ein width*height-String aus einer festen Menge. Man kann es als Raster aus fünf Seitenverhältnissen × zwei Qualitätsstufen lesen:

Seitenverhältnis 720-Stufe 1080-Stufe
16:9 Querformat 1280*720 1920*1080
9:16 Hochformat 720*1280 1080*1920
1:1 Quadrat 1280*1280 1808*1808
4:3 1280*960 1920*1440
3:4 960*1280 1440*1920

Wähle die Zeile nach Platzierung (Hochformat 720*1280 / 1080*1920 für Reels und TikTok, die Querformat-Zeile für YouTube-In-Stream-Anzeigen) und die Spalte nach dem Kompromiss zwischen Bildqualität und Budget. Die Abrechnung erfolgt nach Ausgabesekunden, und die Stufe bestimmt den Sekundenpreis – Details unter Preise; die Mindestabrechnung beträgt 3 Sekunden Clip.

Minimale Anfrage (curl)

Zwei Schritte: absenden, dann pollen.

# 1) Absenden – gibt eine taskId zurück
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vidu-q3-ad/reference-to-video",
    "input": {
      "prompt": "Ein Produktwerbespot der Titan-Smartwatch aus Referenzbild 1: Sie dreht sich langsam auf einem dunklen, reflektierenden Podest, während ein harter Lichtstreifen von links nach rechts über das gebürstete Gehäuse streicht, der Bildschirm bleibt dunkel, die Kamera hält einen niedrigen Hero-Winkel. Werbebeleuchtung, hoher Kontrast, Makro-Detail.",
      "reference_image_urls": [
        "https://your-cdn.com/watch-front.png",
        "https://your-cdn.com/watch-side.png"
      ],
      "duration": 5,
      "size": "1280*720"
    }
  }'
# -> {"data":{"taskId":"..."}}

# 2) Pollen, bis data.status "success" oder "fail" ist
curl -s https://api.hiapi.ai/v1/tasks/THE_TASK_ID \
  -H "Authorization: Bearer sk-your-key"
# Erfolg -> data.status == "success", und data.output[0].url ist das MP4

Die Referenzbild-URLs müssen öffentlich erreichbar sein – die Aufgabe ruft sie serverseitig ab, daher funktionieren weder localhost noch signierte URLs, die in wenigen Sekunden ablaufen.

Python: absenden, pollen, herunterladen

import time
import requests  # oder urllib/subprocess verwenden, um abhängigkeitsfrei zu bleiben

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

def submit():
    payload = {
        "model": "vidu-q3-ad/reference-to-video",
        "input": {
            "prompt": "Werbebild des Sneakers aus Referenzbild 1, der auf einem beleuchteten Drehteller rotiert, "
                      "langsames Push-in, weiches Rim-Light, Produkt-Hero-Framing.",
            "reference_image_urls": ["https://your-cdn.com/sneaker.png"],
            "duration": 5,
            "size": "1080*1920",   # Hochformat 1080p, für Reels / TikTok
        },
    }
    body = requests.post(API, headers=HEADERS, json=payload, timeout=60).json()
    task_id = (body.get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"submit rejected: {body}")   # 400 landet hier
    return task_id

def wait(task_id, timeout_s=600, interval=5):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        data = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30).json().get("data") or {}
        status = data.get("status")
        if status == "success":
            return data["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {data.get('error')}")
        time.sleep(interval)
    raise TimeoutError(task_id)

url = wait(submit())
mp4 = requests.get(url, timeout=120).content   # sofort herunterladen – die Ausgabe-URL läuft ab
open("ad.mp4", "wb").write(mp4)

Das Rendering von Q3-ad ist normalerweise in ein bis zwei Minuten abgeschlossen; ein Polling-Intervall von 5 Sekunden ist völlig ausreichend. Die Ausgabe-URL ist temporär (mit expireAt), daher solltest du die Bytes sofort nach erfolgreichem Abschluss der Aufgabe herunterladen, statt sie per Hotlink in eine Seite einzubinden.

Muster für die Produktion

Callback statt Polling. In serverseitigen Szenarien hänge ein callback auf oberster Ebene an, damit du keine Polling-Schleife aufrechterhalten musst:

{
  "model": "vidu-q3-ad/reference-to-video",
  "input": { "prompt": "...", "reference_image_urls": ["..."], "duration": 5 },
  "callback": { "url": "https://your-app.com/hooks/hiapi", "when": "final" }
}

when unterstützt nur "final" – der Hook wird einmal ausgelöst, wenn die Aufgabe einen Endzustand erreicht, und sein Request-Body entspricht der Nutzlast, die GET /v1/tasks/{taskId} zurückgibt. Hooks können wiederholt werden, also dedupliziere nach taskId und behalte ein langsames Polling als Fallback, falls eine Zustellung verloren geht.

Verzweige nach dem Response-Body, nicht nach dem HTTP-Statuscode. Ein fehlgeschlagenes Rendering gibt weiterhin HTTP 200 zurück; die Fehlerinformation steht in data.status == "fail", Details in data.error. Nur Ablehnungen auf Anfrageebene (Feld-Fehler, fehlender Schlüssel, nicht authentifiziert) verwenden 4xx und geben {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null} zurück.

Idempotenz. Jede Einreichung erzeugt eine neue abgerechnete Aufgabe, also speichere die taskId in dem Moment, in dem du sie erhältst, und polle bei Wiederholungen diese ID erneut. Sende niemals neu, nur weil eine einzelne Polling-Anfrage in eine Zeitüberschreitung gelaufen ist.

Was ich verifiziert habe

Ich habe den Live-Endpunkt mit ungültigen Werten geprüft, die bereits in der Validierungsphase kostenlos abgelehnt werden – es wird keine Aufgabe erstellt und nichts abgerechnet (ungültige Werte scheitern, bevor irgendein Rendering beginnt, was sicherer ist, als ein Feld wegzulassen). Die echten Antworten sind das Schema:

  • Nahezu leerer Request-Body → reference_image_urls: missing required field ...; duration: missing required field .... Daher sind prompt, reference_image_urls und duration alle Pflichtfelder.
  • duration: 99999 → maximum: got 99,999, want 15; duration: 1 → minimum: got 1, want 3; duration: 4.5 → got number, want integer. Duration ist eine ganze Zahl von 3–15.
  • reference_image_urls mit 8 Einträgen → maxItems: got 8, want 7. Das Maximum liegt bei 7.
  • size: "9000p" → value must be one of '1280*720', '1280*960', '1280*1280', '960*1280', '720*1280', '1920*1080', '1920*1440', '1808*1808', '1440*1920', '1080*1920'.
  • aspect_ratio und resolution → beide geben additional properties ... not allowed zurück. Sie sind keine Felder von q3-ad; verwende size.
  • reference_audio_urls als korrekt formatiertes Array übergeben → additional properties 'reference_audio_urls' not allowed. (Bei Übergabe als Nicht-Array wird zuerst eine separate Medienprüfung ausgelöst – „must be an array“ – was irreführend ist: Das Feld ist schlicht nicht im Schema.) Diese Stufe hat keinen Spracheingang; Audio wird nativ generiert.

Dies ist eine Integrationsreferenz und enthält daher keine Qualitätsaussagen – ich habe für diesen Artikel kein kostenpflichtiges Rendering ausgeführt. Wie ein erfolgreiches output[0].url aussieht, zeigt die Modellseite unten mit dem mitgelieferten Beispiel des Endpunkts: ein echtes MP4 mit Tonspur.

Verwandte Anleitungen

Häufige Fragen

Wie mache ich den Clip hoch- oder querformatig? Über size, nicht über aspect_ratio. Für Hochformat 720*1280 oder 1080*1920 verwenden, für Querformat 1280*720 oder 1920*1080.

Kann ich eine Sprechstimme oder eine Audioreferenz bereitstellen? In dieser Stufe nicht – reference_audio_urls wird abgelehnt. Q3-ad generiert sein Audio selbst nativ. Wenn du Audio mithilfe von Referenzclips steuern musst, verwende die reference-to-video-Stufe von Vidu Q4.

Wie viele Produktbilder kann ich senden? Ein bis sieben, in reference_image_urls, und im Prompt per Nummer referenzieren („die Flasche aus Referenzbild 2“).

Meine Aufgabe hat 200 zurückgegeben, aber kein Video – warum? Schau auf data.status. "fail" gibt HTTP 200 zurück, der Grund steht in data.error; nur fehlerhaft geformte Anfragen erhalten 4xx.

Was kostet es? Abgerechnet wird nach Ausgabesekunden, wobei die size-Stufe (720er vs. 1080er) den Sekundenpreis bestimmt. Das Minimum ist ein 3-Sekunden-Clip. Aktuelle Tarife findest du unter Preise.

Ä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