Guide
Generazioni
Come funzionano le generazioni asincrone: stati queued, running, succeeded, failed e canceled, buone pratiche per il polling, output e annullamento.
I modelli video e immagine richiedono da pochi secondi a diversi minuti, quindi ogni richiesta è asincrona. L’invio restituisce subito una generazione; poi puoi controllarne lo stato o ricevere un webhook quando raggiunge uno stato finale. Un oggetto generazione descrive l’intero job: input, stato, output, errore e costo.
Ciclo di vita#
queued se nessuna capacità lo accetta. I job non riusciti o annullati vengono rimborsati integralmente.| Stato | Finale? | Descrizione |
|---|---|---|
queued | No | Accettata, non ancora partita: in attesa nella coda del tuo account (oltre il tuo limite di concorrenza) o di capacità. L'importo è bloccato sul saldo. Puoi ancora annullarla. |
running | No | Il modello sta generando. started_at è impostato. Non è più possibile annullarla. |
succeeded | Sì | Completata. output contiene gli URL dei file multimediali e l'importo bloccato diventa l'addebito finale. |
failed | Sì | Impossibile completarla. error spiega il motivo e l'intero importo bloccato è stato rimborsato. |
canceled | Sì | L'hai annullata mentre era in coda. L'intero importo bloccato è stato rimborsato. |
succeeded, failed e canceled sono stati finali: una generazione non cambia dopo averne raggiunto uno. Considera ogni altro valore “ancora in corso”, così il codice continuerà a funzionare se aggiungiamo stati intermedi.
1. Invio#
POST /api/v1/run/{endpoint} con gli input del modello nel corpo JSON. L’ID endpoint combina il modello e l’attività, per esempio bytedance/seedance-2.0-fast/text-to-video. Trovi tutti gli endpoint e i relativi campi nella pagina Modelli.
Convalidiamo l’input, calcoliamo il prezzo, tratteniamo l’importo dal saldo e mettiamo il job in coda. La risposta è 202 Accepted con la generazione, più urls.get e urls.cancel per comodità:
{
"id": "gen_8c2QmX1nq0k4Lw7Z",
"object": "generation",
"model": "bytedance/seedance-2.0-fast",
"endpoint": "bytedance/seedance-2.0-fast/text-to-video",
"mode": "text-to-video",
"status": "queued",
"input": {
"prompt": "Lento avvicinamento a un ceramista che modella un vaso all’ora dorata, polvere sospesa nella luce, profondità di campo ridotta",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 5,
"generate_audio": true
},
"output": null,
"error": null,
"cost": {
"amount_usd": 0.4494,
"currency": "usd",
"estimated": true
},
"source": "api",
"created_at": "2026-10-15T09:21:04.512Z",
"started_at": null,
"completed_at": null,
"retention": "1d",
"expires_at": null,
"purged_at": null,
"urls": {
"get": "https://cheapergen.com/api/v1/generations/gen_8c2QmX1nq0k4Lw7Z",
"cancel": "https://cheapergen.com/api/v1/generations/gen_8c2QmX1nq0k4Lw7Z/cancel"
}
}Immagini, video e audio di riferimento#
Le modalità reference-to-video accettano fino a tre tipi di riferimenti, ciascuno come elenco di URL HTTPS (link pubblici o URL provenienti da uploads): reference_image_urls per personaggi, prodotti e ambienti; reference_video_urls per movimenti, movimenti di camera ed effetti; reference_audio_urls per voce, musica e suoni.
Indica i riferimenti nel prompt in base alla posizione: @Image1 è il primo URL in reference_image_urls, @Video1 il primo in reference_video_urls, @Audio2 il secondo clip audio e così via. Le menzioni non distinguono tra maiuscole e minuscole e vengono normalizzate in @Image1. Una menzione senza un riferimento corrispondente (per esempio @Video2 con un solo video allegato) viene rifiutata con 400 invalid_request (param: "prompt") prima di qualsiasi addebito.
{
"prompt": "@Image1 dances on a rooftop, copying the choreography and camera move of @Video1, in sync with @Audio1",
"reference_image_urls": [
"https://example.com/dancer.jpg"
],
"reference_video_urls": [
"https://example.com/choreo.mp4"
],
"reference_audio_urls": [
"https://example.com/beat.mp3"
],
"resolution": "720p",
"duration": 8
}Quando invii la richiesta, scarichiamo l’inizio di ogni video e file audio di riferimento e verifichiamo durata, dimensioni, risoluzione e frequenza dei fotogrammi effettive rispetto ai limiti del modello. Un file fuori intervallo — una clip di 20 secondi, un video 1080p per un modello che accetta solo 720p, un M4A quando sono richiesti MP3 o WAV, oppure un URL che non risponde — restituisce 400 invalid_request con param impostato sul campo interessato (per esempio reference_video_urls) e un messaggio che indica la clip, prima di qualsiasi addebito. I video di riferimento aggiungono secondi fatturabili; consulta Fatturazione.
| Modello | Immagini | Video | Audio | Regole |
|---|---|---|---|---|
| Seedance 2.0 | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s ciascuno, 15 s in totale · ≤ 50 MB in totale · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | ≤ 12 file in totale; richiede un'immagine o un video |
| Seedance 2.5 | ≤ 30 | ≤ 10 · MP4/MOV · 2–30 s ciascuno, 30 s in totale · ≤ 200 MB ciascuno · 24–60 fps | ≤ 10 · MP3/WAV · 2–30 s ciascuno, 30 s in totale · ≤ 15 MB ciascuno | ≤ 50 file in totale; richiede almeno un riferimento |
| Seedance 2.0 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s ciascuno, 15 s in totale · ≤ 50 MB in totale · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | ≤ 12 file in totale; richiede un'immagine o un video |
| Seedance 2.0 Mini | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s ciascuno, 15 s in totale · ≤ 50 MB in totale · solo da 480p a 720p · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | ≤ 12 file in totale; richiede un'immagine o un video |
| Wan 3.0 | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s ciascuno, 15 s in totale · ≤ 100 MB ciascuno · 16+ fps · riferimento + risultato ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | richiede almeno un riferimento |
| Wan 3.0 Prime | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s ciascuno, 15 s in totale · ≤ 100 MB ciascuno · 16+ fps · riferimento + risultato ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | richiede almeno un riferimento |
| MiniMax H3 | ≤ 5 | ≤ 3 · MP4/MOV · 2–15 s ciascuno, 15 s in totale · ≤ 50 MB ciascuno · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | ≤ 12 file in totale; richiede un'immagine o un video |
| MiniMax H3 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s ciascuno, 15 s in totale · ≤ 50 MB ciascuno · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s ciascuno, 15 s in totale · ≤ 15 MB ciascuno | ≤ 15 file in totale; richiede un'immagine o un video |
I video devono usare H.264 o H.265 in MP4/MOV. Si applicano i limiti più restrittivi della capacità usata da ogni modello: una richiesta accettata qui viene accettata anche a monte. Le immagini e l’audio di riferimento non modificano il prezzo.
2. Controlla il risultato#
GET /api/v1/generations/{id} restituisce lo stato corrente. Anche consultare una generazione la fa avanzare: se è il momento di controllarne lo stato, lo verifichiamo prima di rispondere, quindi il polling non restituisce dati più vecchi di pochi secondi.
const API = "https://cheapergen.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.CHEAPERGEN_API_KEY}` };
const FINAL = new Set(["succeeded", "failed", "canceled"]);
export async function wait(id, timeoutMs = 15 * 60_000) {
let delay = 2000;
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const gen = await fetch(`${API}/generations/${id}`, { headers }).then((r) => r.json());
if (FINAL.has(gen.status)) return gen;
await new Promise((r) => setTimeout(r, delay));
delay = Math.min(delay * 1.5, 10_000); // back off to every 10 s
}
// Giving up: cancel it first, or it still runs and is charged when it finishes (once running it can't be: 409).
await fetch(`${API}/generations/${id}/cancel`, { method: "POST", headers }).catch(() => {});
throw new Error(`Timed out waiting for ${id}`);
}Intervalli di polling consigliati#
- Immagini: ogni 1–2 secondi. La maggior parte termina in meno di 30 secondi.
- Video: ogni 3–5 secondi all’inizio, poi aumenta gradualmente l’intervallo fino a 10 secondi. Una clip di 5 secondi richiede in genere da uno a tre minuti, di più alle risoluzioni elevate.
- Il polling rientra nel limite di richieste. Se esegui molti job contemporaneamente, preferisci i webhook.
3. Usa l’output#
Quando la generazione riesce, output contiene gli URL HTTPS dei media generati. I modelli video restituiscono un solo file:
{
"output": {
"video": {
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.mp4",
"content_type": "video/mp4"
}
}
}I modelli di immagini restituiscono un elenco, con una voce per ogni immagine generata:
{
"output": {
"images": [
{
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.png",
"content_type": "image/png"
}
]
}
}Conserva i risultati che vuoi tenere
Gli URL di output sono disponibili dalla nostra CDN finché il contenuto della generazione non scade: per le generazioni API, per impostazione predefinita 1 giorno dopo il completamento (consulta Conservazione dei dati). Quando il job riesce, copia nel tuo storage gli output che vuoi conservare.Errori e rimborsi#
Se una generazione non riesce, status è failed, error indica il motivo e cosa fare, e cost.amount_usd scende a 0: l'intero importo bloccato è stato restituito al saldo. In caso di interruzioni o errori, il job viene ritentato automaticamente su ogni altro percorso disponibile prima di essere segnato come non riuscito. Non si ritentano invece i rifiuti del filtro di sicurezza o gli input non supportati dal modello: verrebbero rifiutati di nuovo allo stesso modo. Se il servizio di generazione non riesce a scaricare uno dei tuoi file di input, di solito lo scarichiamo noi e riproviamo con una copia ospitata da noi, allo stesso prezzo; input_unreachable di solito significa che non è stato possibile scaricarlo affatto.
{
"status": "failed",
"error": {
"code": "generation_failed",
"message": "ByteDance's safety review for Seedance 2.0 Fast rejected this request (the prompt or an input file).",
"reason": "content_blocked",
"hint": "Describe the character's look instead of naming a copyrighted character or real person, keep it non-explicit, or try another model.",
"retryable": false,
"refunded": true,
"detail": "La richiesta non ha superato il controllo di sicurezza dei contenuti. Modifica il prompt e riprova."
},
"cost": {
"amount_usd": 0,
"currency": "usd",
"estimated": false
}
}code— la categoria generale, invariata dal lancio:generation_failed(l’input è stato rifiutato o non è stato possibile completarlo),upstream_error,timeoutomodel_unavailable.reason— indica il motivo esatto, descritto nella tabella seguente. Per le nuove integrazioni, usa questo valore nelle condizioni; in futuro potrebbero aggiungersi altri motivi.message— descrive cosa è successo in termini comprensibili agli utenti. Se il filtro di sicurezza rifiuta la richiesta, indica il fornitore cui appartiene il filtro (quello del modello).hint— cosa modificare o fare dopo.retryable—trueindica che un nuovo invio della stessa richiesta può riuscire;falseindica che fallirebbe allo stesso modo.refunded—trueindica che l’importo è stato rimborsato. Le generazioni non riuscite non vengono mai addebitate.param— il campo di input da modificare, se riusciamo a identificarlo (per esempioimage_url,duration).detail— la formulazione originale del fornitore del modello, quando aggiunge informazioni.
| error.reason | error.code | Cosa è successo | Cosa fare | Reinviare così com'è? |
|---|---|---|---|---|
content_blocked | generation_failed | Il filtro di sicurezza del fornitore del modello ha rifiutato il prompt, un file di input o il risultato generato (per esempio un personaggio protetto da copyright, una persona reale o contenuti espliciti). Il messaggio indica a chi appartiene il filtro. | Riformula il prompt (descrivi l’aspetto invece di citare un personaggio, un marchio o una persona reale), usa altri file di input oppure prova un modello di un altro fornitore. Se invii di nuovo la richiesta senza modificarla, verrà rifiutata allo stesso modo. | No — modificalo prima |
invalid_input | generation_failed | Il modello non ha potuto accettare uno degli input o delle impostazioni: un file troppo grande, in un formato non supportato, con dimensioni o proporzioni errate, troppo lungo oppure un valore non supportato. param indica il campo, se riusciamo a identificarlo. | Correggi il campo indicato (consulta i limiti del modello nella relativa pagina API) e invia di nuovo la richiesta, oppure prova un altro modello. | No — modificalo prima |
input_unreachable | generation_failed | Non è stato possibile scaricare un URL di input: richiede l'accesso, il link firmato è scaduto, non punta direttamente al file oppure il server che lo ospita ha rifiutato la richiesta. Quando il servizio di generazione non riesce a scaricare un file, di solito lo scarichiamo noi e riproviamo usando la nostra copia; quindi, nella maggior parte dei casi, significa che non è stato possibile scaricare affatto il file. | Usa un URL pubblico che punti direttamente al file (oppure caricalo con POST /api/v1/uploads) e invia di nuovo la richiesta. | No — modificalo prima |
upstream_unavailable | upstream_error | Il fornitore del modello era non disponibile, sovraccarico o senza capacità; abbiamo provato tutti i percorsi idonei. | Riprova tra un minuto o due oppure usa un altro modello. | Sì |
upstream_error | upstream_error | Il fornitore ha riscontrato un errore interno durante la generazione, dopo che abbiamo provato tutti i percorsi idonei. | Riprova: di solito questi errori sono temporanei. Se il problema persiste, prova un altro modello. | Sì |
timeout | timeout | La generazione non è terminata in tempo (per il limite del fornitore o il nostro limite di 40 minuti). | Riprova. Le clip più brevi o a risoluzione inferiore si completano prima. | Sì |
output_unavailable | upstream_error | Il modello ha terminato, ma non ha restituito un file utilizzabile oppure non è stato possibile scaricare e salvare il risultato. | Retry. | Sì |
model_unavailable | model_unavailable | Il modello, o questa sua modalità, ha smesso di essere disponibile mentre la generazione era in corso. | Scegli un altro modello oppure riprova più tardi. | No — modificalo prima |
canceled | upstream_error | Il fornitore ha annullato o fatto scadere il job prima del completamento. (Una generazione che annulli tu ha stato canceled e non ha errori.) | Retry. | Sì |
generation_failed | generation_failed | Il modello si è interrotto senza restituire un risultato né spiegare il motivo. | Riprova una volta; se fallisce di nuovo, semplifica il prompt o gli input oppure prova un altro modello. | Sì |
Le generazioni non riuscite prima dell’introduzione di reason conservano il codice code originale; anche reason e hint vengono compilati.
Prezzo di emergenza#
Se la capacità abituale per una richiesta non è disponibile, la generazione può essere eseguita su una capacità più costosa al prezzo di emergenza, che non supera mai il prezzo ufficiale del modello. allow_fallback_price determina il comportamento e, per impostazione predefinita, vale true nell'API REST e in MCP: le nuove richieste ricevono un preventivo e vengono addebitate al prezzo di emergenza; un job già accettato al prezzo standard può passare al prezzo di emergenza se la capacità viene meno durante l'esecuzione (il costo aggiuntivo viene bloccato in quel momento). max_cost_usd pone un limite a entrambi i prezzi. Invia allow_fallback_price: false per non pagare mai più del prezzo indicato nel preventivo (con un piano piano Pro o Max, un job già accettato può comunque passare a un'altra capacità, al massimo al prezzo standard): per una nuova richiesta viene quindi applicato 503 fallback_price_declined; se un job già accettato deve passare al prezzo di emergenza, non viene eseguito e ti viene rimborsato. I job di Studio non passano mai a un prezzo più alto dopo il clic. Quando si applica, la generazione indica pricing.fallback (anche nei webhook), insieme a entrambi i prezzi.
Controllo di sicurezza#
enable_safety_checker è attivo per impostazione predefinita: true. Puoi inviare false tramite API; nello Studio e nelle pagine dei modelli è sempre attivo. Il suo funzionamento varia in base al modello:
- Modelli proprietari (Seedance, Kling, Veo, MiniMax H3, Wan 3.0…) usano la moderazione dei rispettivi laboratori, che non può essere disattivata. Accettano
trueefalse, e l’opzione non ha effetto in nessuno dei due casi, quindi non compare nei rispettivi schemi. MiniMax H3 Max fa eccezione: consente di disattivare il filtro, perciò include l’opzione nel proprio schema. Per queste richieste si applica una configurazione di sicurezza specifica del modello — eventualmente al prezzo di emergenza, che non supera mai il prezzo ufficiale. - Seedream 4.5 and Seedream 5.0 Lite la indicano anch'essi. Se il filtro è disattivato, la richiesta viene eseguita sulla configurazione internazionale del modello gestita da ByteDance, che non applica filtri aggiuntivi; se è attivo, si applicano i filtri consueti. Il nostro controllo continua a bloccare qualsiasi contenuto sessuale che coinvolga minori. Le richieste con il filtro disattivato hanno un prezzo dedicato, più alto: Seedream 4.5 $0.04 per image · Seedream 5.0 Lite $0.035 per image.
/quotelo restituisce quando inviienable_safety_checker: false(confallback.reason"safety_checker_off"). È considerata una richiesta prezzo di emergenza: conallow_fallback_price: falseviene rifiutata. Se non è possibile eseguirla in quel momento, la richiesta viene rifiutata con503 model_unavailable(param: "enable_safety_checker"): inviatrueper eseguirla con il filtro standard. - Modelli open-weight lo indicano. Se una generazione viene eseguita con capacità che non dispone di un proprio filtro, il nostro sistema controlla prima il prompt e le immagini di input: se l’opzione è attiva, blocca contenuti sessuali, violenza esplicita e autolesionismo; se è disattivata, blocca comunque qualsiasi contenuto sessuale che coinvolga minori. Se la capacità dispone di un filtro attivabile o disattivabile, l’opzione gli viene passata così come l’hai inviata; anche in questo caso, se è disattivata, il nostro sistema blocca comunque qualsiasi contenuto sessuale che coinvolga minori.
false in una modalità che non mostra l’opzione (e non consente di disattivare il filtro) restituisce 400 invalid_request. Disattivarla non autorizza contenuti vietati dalla nostra Politica di utilizzo accettabile.
Conservazione dei dati#
Le Generazioni API vengono conservate per 1 giorno per impostazione predefinita, a partire dal completamento. Dopo, eliminiamo automaticamente prompt, media di input, output e relativi file. La generazione resta registrata con modello, parametri di prezzo, costo e timestamp, così cronologia d’uso e fatture rimangono accurate: output diventa null, viene impostato purged_at e content_expired spiega il motivo. Scarica gli output da conservare prima di expires_at.
retention | I contenuti vengono eliminati |
|---|---|
immediate | 10 minuti dopo la consegna del risultato — quando il webhook viene accettato o quando leggi la generazione completata con GET — così hai ancora tempo per scaricare i file. Al più tardi, 1 ora dopo il completamento. |
1h | Un'ora dopo il completamento. |
1d | Un giorno dopo il completamento. Valore predefinito. |
7d, 30d | 7 o 30 giorni dopo il completamento. Solo per account Enterprise. |
Passa retention nel corpo della richiesta per scegliere la durata di conservazione per ogni generazione. Qualsiasi account può ridurla (o richiedere fino a 1d); 7d e 30d richiedono un’impostazione di conservazione a livello di account — contatta il team commerciale. Le richieste con durata superiore a quella consentita dall’account restituiscono 400 invalid_request con param: "retention".
{
"prompt": "A paper boat drifting down a rain-soaked street",
"resolution": "720p",
"duration": 5,
"retention": "immediate",
"webhook_url": "https://example.com/hooks/cheapergen"
}Generazioni da Studio e dal playground vengono conservate finché non le elimini. Caricamenti rimangono disponibili finché una generazione conservata le usa; i file non utilizzati da alcuna generazione vengono eliminati dopo 1 giorno. Eliminando l’account vengono eliminate tutte le generazioni e tutti i file. Quando il fornitore del modello ci consente di scegliere, gli chiediamo anche di conservare il minimo possibile dei dati.
Eliminare una generazione#
Elimina qualsiasi generazione completata con DELETE /api/v1/generations/{id}, dall'elenco delle generazioni nella dashboard o dal visualizzatore di Studio; tramite API anche una in coda, finché può ancora essere annullata (viene prima annullata e l'importo bloccato rimborsato per intero). File, prompt e input vengono rimossi subito e la generazione scompare dagli elenchi; l'addebito resta nella cronologia di fatturazione. Consulta la Riferimento API.
Annullare#
POST /api/v1/generations/{id}/cancel annulla una generazione mentre è ancora nello stato queued e rimborsa l’importo trattenuto. Una volta che il job è nello stato running, il modello è già al lavoro: annullarlo restituisce 409 conflict e il job viene completato (e addebitato) normalmente. Alcuni modelli non consentono di annullare un job una volta in coda; anche in quel caso restituiscono 409.
curl -X POST https://cheapergen.com/api/v1/generations/gen_8c2QmX1nq0k4Lw7Z/cancel \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Elencare le generazioni#
GET /api/v1/generations elenca le tue generazioni dalla più recente alla più vecchia, con paginazione tramite cursore. Filtra per status, model o source (playground, api, mcp); passa il next_cursor restituito come cursor per ottenere la pagina successiva. Dettagli in Riferimento API.
curl "https://cheapergen.com/api/v1/generations?status=succeeded&limit=50" \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Qui compaiono anche le generazioni create in Studio e nel Playground delle pagine dei modelli, con source: "playground"; le richieste API hanno source: "api".
Qualcosa non è chiaro o manca? Scrivi a support@cheapergen.com: leggiamo ogni messaggio.