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.
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-videoeflux-3-max/keyframes-to-video. Per cambiare modalità basta modificaremodele 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.urlewhen: "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
taskIdprima di iniziare il polling, per evitare che un crash del programma faccia perdere attività già pagate. - Scarica subito. Considera
output[0].urlvalido 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.
Articoli correlati
Vedi tutti gli articoli →-
Tutoriale
Come chiamare hailuo-2.3-fast/image-to-video tramite l'API HiAPI: pratica con curl e Python
La prima richiesta funzionante per il livello image-to-video veloce ed economico — dall'ID del modello al download di un MP4
-
Tutoriale
Come chiamare hailuo-2.3/text-to-video tramite l'API HiAPI: curl, Python ed esempi di richiesta eseguibili
-
Tutoriale
Utilizzare Kandinsky 6.0 Pro su HiAPI per la generazione di video da testo: tutorial con curl e Python
Dimostrazione pratica guidata dalla richiesta: costruire la chiamata da prompt a clip video, inviare la richiesta, monitorare lo stato di completamento e scaricare il risultato