CheaperGen

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 running succeededfailed
queued canceledtramite POST /generations/{id}/cancel
Un job può fallire già da queued se nessuna capacità lo accetta. I job non riusciti o annullati vengono rimborsati integralmente.
StatoFinale?Descrizione
queuedNoAccettata, 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.
runningNoIl modello sta generando. started_at è impostato. Non è più possibile annullarla.
succeededSìCompletata. output contiene gli URL dei file multimediali e l'importo bloccato diventa l'addebito finale.
failedSìImpossibile completarla. error spiega il motivo e l'intero importo bloccato è stato rimborsato.
canceledSì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à:

202 Accepted
{
  "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.

POST /run/bytedance/seedance-2.0/reference-to-video
{
  "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.

Limiti degli input di riferimento per modello
ModelloImmaginiVideoAudioRegole
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 ciascunorichiede 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 ciascunorichiede 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}`);
}
  • 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, timeout o model_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 — true indica che un nuovo invio della stessa richiesta può riuscire; false indica che fallirebbe allo stesso modo.
  • refunded — true indica 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 esempio image_url, duration).
  • detail — la formulazione originale del fornitore del modello, quando aggiunge informazioni.
error.reasonerror.codeCosa è successoCosa fareReinviare così com'è?
content_blockedgeneration_failedIl 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_inputgeneration_failedIl 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_unreachablegeneration_failedNon è 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_unavailableupstream_errorIl 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_errorupstream_errorIl 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ì
timeouttimeoutLa 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_unavailableupstream_errorIl modello ha terminato, ma non ha restituito un file utilizzabile oppure non è stato possibile scaricare e salvare il risultato.Retry.Sì
model_unavailablemodel_unavailableIl 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
canceledupstream_errorIl 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_failedgeneration_failedIl 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 true e false, 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. /quote lo restituisce quando invii enable_safety_checker: false (con fallback.reason "safety_checker_off"). È considerata una richiesta prezzo di emergenza: con allow_fallback_price: false viene rifiutata. Se non è possibile eseguirla in quel momento, la richiesta viene rifiutata con 503 model_unavailable (param: "enable_safety_checker"): invia true per 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.

retentionI contenuti vengono eliminati
immediate10 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.
1hUn'ora dopo il completamento.
1dUn giorno dopo il completamento. Valore predefinito.
7d, 30d7 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".

POST /run/bytedance/seedance-2.0-fast/text-to-video
{
  "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.