Guides
Générations
Fonctionnement des générations asynchrones : états queued, running, succeeded, failed et canceled, bonnes pratiques d’interrogation, résultats et annulation.
Les modèles vidéo et image mettent de quelques secondes à plusieurs minutes à générer un résultat ; chaque requête est donc asynchrone. L’envoi renvoie immédiatement un génération. Vous pouvez ensuite l’interroger ou recevoir un webhook lorsqu’il atteint un état final. Un seul objet de génération décrit toute la tâche : ses entrées, son état, son résultat, son erreur et son coût.
Cycle de vie#
queued si aucune capacité ne l’accepte. Les tâches échouées ou annulées sont intégralement remboursées.| État | Final ? | Signification |
|---|---|---|
queued | Non | Acceptée, pas encore démarrée : en attente dans la file de votre compte (au-delà de votre limite de concurrence) ou d’une capacité disponible. Le montant est réservé sur votre solde. Vous pouvez encore l’annuler. |
running | Non | Le modèle génère le résultat. started_at est défini. L’annulation n’est plus possible. |
succeeded | Oui | Terminée. output contient les URL des médias et le montant réservé devient le débit final. |
failed | Oui | Échec. error en indique le motif et le montant réservé a été intégralement remboursé. |
canceled | Oui | Vous l’avez annulée pendant qu’elle était en attente. Le montant réservé a été intégralement remboursé. |
succeeded, failed et canceled sont des états finaux : une génération ne change plus une fois qu’elle les a atteints. Considérez toute autre valeur comme « en cours » ; votre code restera ainsi compatible avec l’ajout éventuel d’états intermédiaires.
1. Envoyer#
POST /api/v1/run/{endpoint} avec les entrées du modèle dans le corps JSON. L’identifiant du point de terminaison combine le modèle et la tâche, par exemple bytedance/seedance-2.0-fast/text-to-video. Retrouvez tous les points de terminaison et leurs champs sur la page Modèles.
Nous validons les entrées, calculons le prix, le réservons sur votre solde et mettons la tâche en file d’attente. La réponse est 202 Accepted avec la génération, ainsi que urls.get et urls.cancel pour plus de commodité :
{
"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": "Travelling avant lent sur un céramiste qui façonne un vase à l’heure dorée, poussière dans la lumière, faible profondeur de champ",
"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"
}
}Images, vidéos et audio de référence#
Les modes reference-to-video acceptent jusqu’à trois types de références, chacun sous forme de liste d’URL HTTPS (liens publics ou URL provenant de uploads) : reference_image_urls pour les personnages, produits et décors, reference_video_urls pour les mouvements, mouvements de caméra et effets, et reference_audio_urls pour la voix, la musique et les sons.
Indiquez leur position dans le prompt : @Image1 correspond à la première URL de reference_image_urls, @Video1 à la première URL de reference_video_urls, @Audio2 au deuxième clip audio, etc. Les mentions ne sont pas sensibles à la casse et sont normalisées en @Image1. Une mention sans référence correspondante (par exemple @Video2 avec une seule vidéo jointe) est rejetée avec 400 invalid_request (param: "prompt") avant toute facturation.
{
"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
}Lorsque vous envoyez une requête, nous téléchargeons le début de chaque fichier vidéo ou audio de référence et vérifions sa durée, sa taille, sa résolution et sa fréquence d’images réelles par rapport aux limites du modèle. Tout fichier hors limites — clip de 20 secondes, vidéo 1080p pour un modèle limité au 720p, fichier M4A quand seuls MP3 ou WAV sont acceptés, URL sans réponse — renvoie 400 invalid_request, avec param défini sur le champ concerné (par exemple reference_video_urls) et un message qui nomme le clip, avant toute facturation. Les vidéos de référence ajoutent des secondes facturées ; voir Facturation.
| Modèle | Images | Vidéos | Audio | Règles |
|---|---|---|---|---|
| Seedance 2.0 | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s chacune, 15 s au total · ≤ 50 MB au total · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s chacune, 15 s au total · ≤ 15 MB chacune | ≤ 12 fichiers au total; nécessite une image ou une vidéo |
| Seedance 2.5 | ≤ 30 | ≤ 10 · MP4/MOV · 2–30 s chacune, 30 s au total · ≤ 200 MB chacune · 24–60 fps | ≤ 10 · MP3/WAV · 2–30 s chacune, 30 s au total · ≤ 15 MB chacune | ≤ 50 fichiers au total; nécessite au moins une référence |
| Seedance 2.0 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s chacune, 15 s au total · ≤ 50 MB au total · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s chacune, 15 s au total · ≤ 15 MB chacune | ≤ 12 fichiers au total; nécessite une image ou une vidéo |
| Seedance 2.0 Mini | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s chacune, 15 s au total · ≤ 50 MB au total · 480p–720p uniquement · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s chacune, 15 s au total · ≤ 15 MB chacune | ≤ 12 fichiers au total; nécessite une image ou une vidéo |
| Wan 3.0 | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s chacune, 15 s au total · ≤ 100 MB chacune · 16+ fps · référence + résultat ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s chacune, 15 s au total · ≤ 15 MB chacune | nécessite au moins une référence |
| Wan 3.0 Prime | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s chacune, 15 s au total · ≤ 100 MB chacune · 16+ fps · référence + résultat ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s chacune, 15 s au total · ≤ 15 MB chacune | nécessite au moins une référence |
| MiniMax H3 | ≤ 5 | ≤ 3 · MP4/MOV · 2–15 s chacune, 15 s au total · ≤ 50 MB chacune · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s chacune, 15 s au total · ≤ 15 MB chacune | ≤ 12 fichiers au total; nécessite une image ou une vidéo |
| MiniMax H3 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s chacune, 15 s au total · ≤ 50 MB chacune · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s chacune, 15 s au total · ≤ 15 MB chacune | ≤ 15 fichiers au total; nécessite une image ou une vidéo |
Les vidéos doivent être au format MP4 ou MOV avec codec H.264 ou H.265. Les limites correspondent à la capacité la plus restrictive sur laquelle chaque modèle peut être exécuté ; une requête qui passe ces vérifications peut donc être acceptée par le service du modèle. Les images et fichiers audio de référence ne modifient pas le prix.
2. Interroger le résultat#
GET /api/v1/generations/{id} renvoie l’état actuel. La lecture d’une génération la fait également avancer : si une vérification d’état est due, elle est effectuée avant la réponse. Les résultats de l’interrogation ont ainsi quelques secondes de retard au maximum.
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}`);
}Fréquences d’interrogation recommandées#
- Images : Interrogez les générations toutes les 1 à 2 secondes. La plupart se terminent en moins de 30 secondes.
- Vidéo : Interrogez les générations vidéo toutes les 3 à 5 secondes au début, puis espacez les requêtes jusqu’à 10 secondes. Un clip de 5 secondes prend généralement une à trois minutes, et davantage en haute résolution.
- L’interrogation compte dans votre limite limite de débit. Si vous exécutez de nombreuses tâches à la fois, privilégiez webhooks.
3. Utiliser le résultat#
En cas de réussite, output contient les URL HTTPS des médias générés. Les modèles vidéo renvoient un seul fichier :
{
"output": {
"video": {
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.mp4",
"content_type": "video/mp4"
}
}
}Les modèles d’image renvoient une liste, avec une entrée par image générée :
{
"output": {
"images": [
{
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.png",
"content_type": "image/png"
}
]
}
}Enregistrer les résultats à conserver
Les URL de résultat sont hébergées sur notre CDN jusqu’à l’expiration du contenu de la génération — par défaut, 1 jour après sa fin pour les générations API (voir Conservation des données). Copiez les résultats à conserver vers votre propre espace de stockage dès que la tâche réussit.Échecs et remboursements#
En cas d’échec d’une génération, status est failed, error indique le motif et la marche à suivre, et cost.amount_usd passe à 0 — la totalité du montant réservé a été recréditée sur votre solde. Les pannes et erreurs de fournisseurs sont automatiquement retentées sur chaque autre route éligible avant qu’une tâche soit déclarée en échec. Ce n’est pas le cas d’un rejet par filtre de sécurité ou d’une entrée incompatible avec le modèle : la même requête serait de nouveau rejetée. Si un fournisseur ne peut pas télécharger l’un de vos fichiers d’entrée, nous essayons généralement de le télécharger nous-mêmes et relançons la tâche avec notre copie, au même prix ; input_unreachable signifie le plus souvent qu’il n’a pas pu être téléchargé.
{
"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": "Votre requête n’a pas passé le contrôle de sécurité du contenu. Modifiez votre prompt et réessayez."
},
"cost": {
"amount_usd": 0,
"currency": "usd",
"estimated": false
}
}code— la catégorie générale, inchangée depuis le lancement :generation_failed(entrée rejetée ou impossible à traiter),upstream_error,timeoutoumodel_unavailable.reason— la raison précise, indiquée dans le tableau ci-dessous. Utilisez ce champ dans les nouvelles intégrations ; de nouvelles raisons pourront être ajoutées.message— ce qui s’est passé, expliqué en termes que vous pouvez montrer aux utilisateurs. En cas de rejet par un filtre de sécurité, ce champ précise à qui appartient le filtre (au fournisseur du modèle).hint— ce qu’il faut modifier ou faire ensuite.retryable—true: renvoyer la même requête peut réussir ;false: elle échouerait de nouveau.refunded—truesi le montant réservé a été recrédité. Les générations échouées ne sont jamais facturées.param— champ d’entrée à modifier, si nous pouvons l’identifier (par exempleimage_url,duration).detail— formulation propre au fournisseur du modèle, lorsqu’elle apporte une précision.
| error.reason | error.code | Que s’est-il passé ? | Que faire ? | Renvoyer tel quel ? |
|---|---|---|---|---|
content_blocked | generation_failed | Le filtre de sécurité du fournisseur du modèle a rejeté le prompt, un fichier d’entrée ou le résultat généré (par exemple, un personnage protégé nommé, une personne réelle ou du contenu explicite). Le message indique à qui appartient le filtre. | Reformulez le prompt (décrivez l’apparence au lieu de nommer un personnage, une marque ou une personne réelle), utilisez d’autres fichiers d’entrée ou essayez un modèle d’un autre fournisseur. Une requête identique échouera de la même façon. | Non — à modifier d’abord |
invalid_input | generation_failed | Le modèle n’a pas accepté l’une des entrées ou des options : fichier trop volumineux, format non pris en charge, dimensions ou proportions incorrectes, durée excessive ou valeur incompatible. Lorsque nous pouvons l’identifier, param indique le champ concerné. | Corrigez le champ indiqué (consultez les limites du modèle sur sa page API) et renvoyez la requête, ou essayez un autre modèle. | Non — à modifier d’abord |
input_unreachable | generation_failed | Impossible de télécharger une URL d’entrée : elle nécessite une connexion, le lien signé a expiré, ne pointe pas directement vers le fichier ou l’hébergeur a refusé la requête. Lorsque le fournisseur du modèle ne peut pas récupérer un fichier, nous le téléchargeons généralement nous-mêmes et relançons la tâche avec notre copie. Cela signifie le plus souvent que le fichier n’a pas pu être téléchargé du tout. | Utilisez une URL publique qui pointe directement vers le fichier (ou importez-le avec POST /api/v1/uploads), puis renvoyez la requête. | Non — à modifier d’abord |
upstream_unavailable | upstream_error | Le fournisseur du modèle était indisponible, surchargé ou à pleine capacité ; nous avons essayé toutes les routes disponibles. | Réessayez dans une ou deux minutes ou utilisez un autre modèle. | Oui |
upstream_error | upstream_error | Après avoir essayé toutes les routes disponibles, le fournisseur a rencontré une erreur interne pendant la génération. | Réessayez ; ces erreurs sont généralement temporaires. Si le problème persiste, essayez un autre modèle. | Oui |
timeout | timeout | La génération n’a pas abouti à temps (limite du fournisseur ou limite de 40 minutes imposée par nos soins). | Réessayez. Les clips plus courts ou de résolution inférieure sont générés plus rapidement. | Oui |
output_unavailable | upstream_error | Le modèle a terminé la génération, mais n’a renvoyé aucun fichier exploitable, ou le résultat n’a pas pu être téléchargé et enregistré. | Retry. | Oui |
model_unavailable | model_unavailable | Le modèle, ou ce mode du modèle, a cessé d’être fourni pendant la génération. | Choisissez un autre modèle ou réessayez plus tard. | Non — à modifier d’abord |
canceled | upstream_error | Le fournisseur a annulé la tâche ou l’a laissée expirer avant son terme. (Une génération que vous annulez vous-même porte l’état canceled et n’a pas d’erreur.) | Retry. | Oui |
generation_failed | generation_failed | Le modèle s’est arrêté sans résultat et sans indiquer de raison. | Réessayez une fois ; en cas de nouvel échec, simplifiez le prompt ou les entrées, ou essayez un autre modèle. | Oui |
Les générations ayant échoué avant l’existence de reason conservent leur valeur initiale code ; reason et hint sont également renseignés pour ces générations.
Tarif d’urgence#
Lorsqu’une requête ne peut pas être exécutée sur la capacité habituelle, elle peut utiliser une capacité plus coûteuse au tarif d’urgence, qui ne dépasse jamais le tarif officiel du modèle. allow_fallback_price détermine ce comportement ; sa valeur par défaut est true pour l’API REST et MCP : une nouvelle requête reçoit un devis au tarif d’urgence et est facturée à ce tarif ; une tâche déjà acceptée au tarif standard peut aussi être basculée vers cette capacité si celle-ci échoue en cours de traitement (le supplément est alors réservé). max_cost_usd plafonne les deux tarifs. Envoyez allow_fallback_price: false pour ne jamais payer plus que le prix indiqué dans votre devis (avec un forfait Pro ou Max, une tâche acceptée peut sinon aussi passer à un prix supérieur, au plus au tarif standard) : une nouvelle requête reçoit alors 503 fallback_price_declined, tandis qu’une tâche acceptée échouera et sera remboursée. Les tâches lancées dans Studio ne passent jamais à un tarif supérieur après votre clic. Le champ pricing.fallback (également présent dans les webhooks) le signale, avec les deux tarifs.
Vérification de sécurité#
enable_safety_checker est défini par défaut sur true. Vous pouvez transmettre false via l’API ; il est toujours activé dans Studio et sur les pages des modèles. Son effet dépend du modèle :
- Les modèles à poids fermés (Seedance, Kling, Veo, MiniMax H3, Wan 3.0…) intègrent la modération propre à leur laboratoire, que personne ne peut désactiver. Ils acceptent
trueetfalse, et aucun des deux ne change quoi que ce soit ; l’option ne figure donc pas dans leur schéma. MiniMax H3 Max fait exception : il permet de désactiver le filtre, et l’option figure donc dans son schéma. Ces requêtes utilisent sa propre configuration de sécurité — éventuellement au tarif d’urgence, sans jamais dépasser le tarif officiel. - Seedream 4.5 and Seedream 5.0 Lite le mentionnent également. Lorsqu’il est désactivé, la requête utilise la configuration internationale du modèle propre à ByteDance, sans filtre supplémentaire ; lorsqu’il est activé, les filtres habituels s’appliquent. Notre contrôle bloque toujours tout contenu sexuel impliquant des mineurs. Les requêtes avec cette option désactivée ont un tarif plus élevé qui leur est propre : Seedream 4.5 $0.04 per image · Seedream 5.0 Lite $0.035 per image.
/quotele renvoie si vous envoyezenable_safety_checker: false(avecfallback.reason"safety_checker_off"). C’est considéré comme un tarif d’urgence : avecallow_fallback_price: false, une telle requête est refusée. Si le modèle ne peut pas la traiter pour le moment, la requête est rejetée avec503 model_unavailable(param: "enable_safety_checker") : envoyeztruepour utiliser le filtre standard. - Les modèles à poids ouverts répertorient cette option. Lorsqu’une génération est exécutée sur une capacité dépourvue de filtre, notre système de contrôle vérifie d’abord le prompt et les images d’entrée : si l’option est activée, il bloque les contenus sexuels, la violence graphique et l’automutilation ; si elle est désactivée, il bloque toujours tout contenu sexuel impliquant des mineurs. Si la capacité possède son propre filtre désactivable, l’option lui est transmise telle quelle ; si elle est désactivée, notre système bloque tout de même tout contenu sexuel impliquant des mineurs.
Appeler false avec un mode qui ne répertorie pas l’option (et ne permet pas de désactiver son système de contrôle) renvoie 400 invalid_request. La désactivation de cette option n’autorise aucun contenu interdit par notre Politique d’utilisation acceptable.
Conservation des données#
Générations API sont conservées par défaut pendant 1 jour à compter de la fin de la génération. Passé ce délai, le prompt, les médias d’entrée, les résultats et leurs fichiers sont automatiquement supprimés. La génération elle-même est conservée avec son modèle, les paramètres déterminant le prix, son coût et ses horodatages, afin que votre historique d’utilisation et vos factures restent exacts : output devient null, purged_at est renseigné et content_expired en indique la raison. Téléchargez les résultats à conserver avant expires_at.
retention | Suppression du contenu |
|---|---|
immediate | 10 minutes après la livraison du résultat — lorsque votre webhook a été accepté ou que vous avez consulté la génération terminée avec GET — afin que vous puissiez encore télécharger les fichiers. Au plus tard 1 heure après la fin de la génération. |
1h | 1 heure après la fin. |
1d | 1 jour après la fin. Valeur par défaut. |
7d, 30d | 7 ou 30 jours après la fin. Comptes Enterprise uniquement. |
Indiquez retention dans le corps de la requête pour choisir la durée de conservation de chaque génération. Tous les comptes peuvent la réduire (ou demander jusqu’à 1d) ; 7d et 30d nécessitent un paramètre de conservation au niveau du compte — contacter l’équipe commerciale. Une demande dépassant la durée autorisée par votre compte renvoie 400 invalid_request avec 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"
}générations Studio et de l’aire de test sont conservées jusqu’à leur suppression. Les Téléversements restent aussi longtemps qu’une génération conservée les utilise ; les fichiers inutilisés par toute génération sont supprimés après 1 jour. La suppression de votre compte efface toutes vos générations et tous vos fichiers. Lorsque le fournisseur du modèle nous en laisse le choix, nous lui demandons également de conserver le moins de données possible.
Supprimer une génération#
Supprimez toute génération terminée avec DELETE /api/v1/generations/{id}, depuis la liste des générations du tableau de bord ou depuis la visionneuse du Studio ; via l’API, une génération en file aussi, tant qu’elle peut encore être annulée (elle est d’abord annulée et son montant réservé remboursé en totalité). Ses fichiers, son prompt et ses entrées sont supprimés immédiatement et elle disparaît des listes ; le débit reste dans votre historique de facturation. Consultez la Référence de l’API.
Annulation#
POST /api/v1/generations/{id}/cancel annule une génération encore à l’état queued et rembourse le montant réservé. Lorsqu’une tâche est running, le modèle a déjà commencé à la traiter : l’annulation renvoie 409 conflict, et la tâche se termine et est facturée normalement. Certains modèles ne permettent pas l’annulation une fois la tâche en attente ; dans ce cas aussi, 409 est renvoyé.
curl -X POST https://cheapergen.com/api/v1/generations/gen_8c2QmX1nq0k4Lw7Z/cancel \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Lister les générations#
GET /api/v1/generations répertorie vos générations, des plus récentes aux plus anciennes, avec une pagination par curseur. Filtrez par status, model ou source (playground, api, mcp) ; transmettez le next_cursor renvoyé comme valeur de cursor pour obtenir la page suivante. Détails dans le Référence de l’API.
curl "https://cheapergen.com/api/v1/generations?status=succeeded&limit=50" \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Les générations lancées depuis Studio et les pages de modèles apparaissent également ici, avec source: "playground" ; les requêtes API indiquent source: "api".
Quelque chose n’est pas clair ou manque ? Écrivez à support@cheapergen.com : nous lisons tous les messages.