HiAPI
Blog

Tutoriale

FLUX 3 Max API: testo a video, immagine a video e keyframe su hiapi

Tre ID modello, un unico flusso /v1/tasks: curl, script di supporto Python, regole della timeline dei keyframe e veri errori di validazione.

Oct 23, 2026
FLUX 3 Max API: testo a video, immagine a video e keyframe su hiapi

Sintesi

  • FLUX 3 Max su hiapi è costituito da tre ID modello distinti sullo stesso endpoint POST /v1/tasks: flux-3-max/text-to-video, flux-3-max/image-to-video e flux-3-max/keyframes-to-video. Per cambiare modalità basta modificare model e un campo di input.
  • Tutti e tre generano clip da 5–20 secondi a 720p o 1080p, con tariffazione basata sui secondi di output e sulla risoluzione. Per i prezzi aggiornati consulta /en/pricing.
  • Le regole sui numeri di frame dei keyframe non vengono verificate al momento dell'invio. Se la timeline è errata l'API restituisce comunque HTTP 200 e un taskId, ma l'attività fallisce dopo circa 2 secondi. Verifica quindi in locale prima di inviare.

Questa guida riguarda la fascia Max. Per il modello base flux-3 con modalità bozza e continuazione video vedi Guida all'API video FLUX.3; per modificare materiale esistente vedi modifica video con flux-3.

Prerequisiti

Crea una chiave nella console hiapi ed esportala:

export HIAPI_KEY=sk-your-key

Il flusso di richiesta è identico per tutte le modalità: POST /v1/tasks restituisce un taskId, poi esegui il polling di GET /v1/tasks/<taskId> (oppure usa un callback) finché status non è success, quindi scarica data.output[0].url.

Quale ID modello corrisponde a quale input

Input di cui disponi ID modello Input da modificare
Solo prompt testuale flux-3-max/text-to-video prompt
Un'immagine statica (facoltativamente più un frame finale) flux-3-max/image-to-video image_url, facoltativamente end_image_url
Da 1 a 10 immagini che devono cadere in momenti specifici flux-3-max/keyframes-to-video keyframes: [{image_url, frame_index}]

Campi facoltativi comuni ai tre modelli: duration (secondi interi, 5–20, predefinito 5), resolution (720p o 1080p), aspect_ratio (auto, 21:9, 2:1, 16:9, 4:3, 1:1, 3:4, 9:16), generate_audio (booleano, attivo per impostazione predefinita) e reasoning_level (low o high, predefinito high). Pagine dei modelli: testo a video, immagine a video, keyframe a video.

Esempio minimo: testo a video con curl

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer $HIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-3-max/text-to-video",
    "input": {
      "prompt": "a slow aerial shot of ocean waves at sunrise, photorealistic",
      "duration": 5,
      "resolution": "720p",
      "generate_audio": false,
      "reasoning_level": "low"
    }
  }'

Se la richiesta è valida restituisce {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}. Poi:

curl https://api.hiapi.ai/v1/tasks/tk-hiapi-... -H "Authorization: Bearer $HIAPI_KEY"

La configurazione con generate_audio disattivato, 5 secondi e ragionamento low è un modo economico per testare l'efficacia di un prompt; la pagina del modello indica che l'audio non modifica il prezzo.

Un unico script di supporto Python per tutte e tre le modalità

# pip install requests
import os, time, requests

KEY = os.environ["HIAPI_KEY"]
H = {"Authorization": f"Bearer {KEY}"}
BASE = "https://api.hiapi.ai/v1/tasks"

def submit(mode: str, **inp) -> str:
    """mode: text-to-video | image-to-video | keyframes-to-video"""
    body = {"model": f"flux-3-max/{mode}", "input": inp}
    res = requests.post(BASE, json=body, headers=H, timeout=30).json()
    if res.get("code") != 200:
        # sync 400s look like {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: ..."}
        raise RuntimeError(res)
    return res["data"]["taskId"]

def wait(task_id: str, timeout_s: int = 900, every: int = 10) -> str:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        d = requests.get(f"{BASE}/{task_id}", headers=H, timeout=30).json()["data"]
        if d["status"] == "success":
            return d["output"][0]["url"]
        if d["status"] == "fail":
            raise RuntimeError(d.get("error"))
        time.sleep(every)
    raise TimeoutError(task_id)

# 1) text-to-video
t2v = submit("text-to-video",
    prompt="A single white sneaker rotates slowly on a wet black plinth, studio softbox lighting, macro product shot",
    duration=5, resolution="720p", aspect_ratio="16:9", generate_audio=False)

# 2) image-to-video: first frame, optional last frame
i2v = submit("image-to-video",
    prompt="Morning mist drifts over the harbor; the boats rock gently and the camera slowly pushes forward.",
    image_url="https://example.com/harbor.jpg",
    # end_image_url="https://example.com/harbor-end.jpg",   # optional fixed ending
    duration=5, resolution="720p", generate_audio=False)

# 3) keyframes-to-video
FPS = 24
def keyframes_ok(duration: int, frames: list[dict]) -> None:
    idx = [f["frame_index"] for f in frames]
    assert 1 <= len(frames) <= 10, "1-10 keyframes"
    assert len(set(idx)) == len(idx), "frame_index must be unique"
    assert all(0 <= i <= duration * FPS for i in idx), f"frame_index must be 0..{duration * FPS}"

frames = [
    {"image_url": "https://example.com/harbor.jpg", "frame_index": 0},
    {"image_url": "https://example.com/latte.jpg",  "frame_index": 120},
]
keyframes_ok(5, frames)
kf = submit("keyframes-to-video",
    prompt="A continuous cinematic morph from the misty harbor into a close-up of an iced matcha latte.",
    keyframes=frames, duration=5, resolution="720p", generate_audio=False)

url = wait(kf)
open("clip.mp4", "wb").write(requests.get(url).content)

Gli URL di output scadono, quindi dopo il successo dell'attività scarica o copia subito il file invece di salvare il link.

Keyframe: come funziona la timeline

frame_index è una posizione su un orologio a 24 fps che parte da 0, non una percentuale. Il valore massimo consentito è duration × 24: 120 per 5 secondi, 240 per 10 secondi, 480 per 20 secondi. Gli indici devono essere univoci e puoi passare da 1 a 10 keyframe. Per ottenere una transizione pulita da A a B, posiziona il primo ancoraggio a 0 e l'ultimo a duration × 24; anticipare l'ultimo ancoraggio mantiene la parte finale, posticiparlo comprime il cambiamento. Mantieni coerente il rapporto d'aspetto di tutti i keyframe; per un ciclo senza soluzione di continuità, fai in modo che le immagini iniziale e finale sembrino lo stesso istante.

Note per la produzione

  • Polling e callback. L'API delle attività accetta callback.url e when: "final", così non devi fare polling; eseguire il polling ogni 10 secondi come sopra va bene comunque per script e attività in batch.
  • Imposta sempre un timeout nel ciclo di polling e salva taskId prima di iniziare il polling, per evitare che un crash del programma faccia perdere attività già pagate.
  • Scarica subito. Considera output[0].url valido per breve tempo.
  • Controllo dei costi. La tariffazione si basa sui secondi di output e sulla risoluzione, quindi una clip da 20 secondi a 1080p costa diverse volte più di un test da 5 secondi a 720p. Inizia con 5 secondi e 720p, poi aumenta entrambi quando il prompt funziona. Le tariffe attuali sono nellapagina dei prezzi.

Cosa ho testato e cosa non ho testato

Queste verifiche sono state eseguite il 23 ottobre 2026 sull'API di produzione con una chiave di test in sola lettura. Questo articolo non ha renderizzato clip complete, quindi non formulo alcuna affermazione sulla qualità dell'output; i prompt di esempio provengono dagli esempi forniti nelle pagine dei modelli.

Validazione sincrona (HTTP 400, non messo in coda). I valori fuori intervallo vengono rifiutati al momento dell'invio, con error_code: INVALID_REQUEST e un message leggibile:

Richiesta Risposta message
duration: 3 invalid input: duration: minimum: got 3, want 5
resolution: "4k" value must be one of '720p', '1080p'
aspect_ratio: "5:4" value must be one of 'auto', '21:9', '2:1', '16:9', '4:3', '1:1', '3:4', '9:16'
reasoning_level: "medium" value must be one of 'low', 'high'
Immagine a video con image_urls invece di image_url image_url: missing required field "image_url"; ... additional properties 'image_urls' not allowed

L'ultima riga è un errore comune: altri modelli con input immagine su hiapi usano un campo al plurale, ma FLUX 3 Max immagine a video accetta solo un singolo image_url. I campi sconosciuti vengono rifiutati, non ignorati.

Gli errori nella timeline dei keyframe sono asincroni. Ho inviato due richieste keyframe da 5 secondi con timeline problematiche: una con frame_index: 121 (oltre il limite di 120), l'altra con entrambi i keyframe a frame_index: 0. Entrambe sono state accettate, restituendo HTTP 200 e un taskId. Circa 1–2 secondi dopo la creazione il polling ha restituito lo stato terminale:

{"code":200,"data":{"status":"fail","model":"flux-3-max/keyframes-to-video",
 "error":{"code":"INVALID_REQUEST","message":"Invalid request parameters for this model. Please check the request and try again."},
 "taskId":"tk-hiapi-..."},"message":"success"}

Da qui due considerazioni. Primo, un invio che restituisce 200 non significa che la timeline sia valida, quindi durante il polling controlla status e error.code. Secondo, il messaggio di errore è generico e non indica quale frame sia problematico: è questo il motivo per cui vale la pena eseguire il controllo keyframes_ok qui sopra prima dell'invio. La pagina del modello indica che le attività fallite non vengono addebitate; non ho verificato la fatturazione di queste due attività.

Domande frequenti

Quale ID modello usare per un primo frame più un frame finale? Usa flux-3-max/image-to-video, passando image_url e end_image_url. Usa i keyframe solo quando devi impostare ancoraggi tra inizio e fine.

Aggiungere keyframe costa di più? Secondo la pagina del modello, no: la tariffazione si basa sui secondi di output e sulla risoluzione, il numero di ancoraggi non influenza il prezzo.

In cosa differisce da flux-3? flux-3-max/* è costituito da ID modello separati, suddivisi per modalità (testo, immagine, keyframe); il modello base flux-3 è invece un unico ID che cambia modalità in base all'input e supporta anche la modalità bozza e la continuazione. Vedi Guida all'API video FLUX.3. Non ho confrontato la qualità dell'output dei due, quindi scegli in base alle funzionalità e alle tariffe della pagina dei prezzi.

Posso usare un altro modello immagine a video? Sì. Per altre soluzioni immagine a video vedi Come usare l'API immagine a video Ray 3.2.

Inizia a creare con artefatti IA persistenti

Ottieni la tua chiave API e chiama modelli di immagini, video e audio tramite un'unica API basata sui task.

Leggi la documentazione API