API Cheaper Gen.
Une API REST asynchrone pour les modèles officiels de vidéo et d'image. La facturation est basée sur un solde USD prépayé : vous payez par seconde de vidéo ou par image, et les générations échouées sont automatiquement remboursées.
- URL de base :
https://cheapergen.com/api/v1 - Authentification :
Authorization: Bearer $CHEAPERGEN_API_KEY(les clés commencent parcg_live_; créez-en une sur https://cheapergen.com/dashboard/keys). Lisez la clé depuis l'environnement. Ne l'imprimez jamais, ne la connectez jamais et ne la commitez jamais. - Préférez le serveur MCP lorsqu'il est connecté. Ses outils sont
list_models,get_model,quote,generate(avecwait_secondset une protection budgétairemax_cost_usd),get_generation,get_accountetadd_credits(un lien de paiement que l'utilisateur ouvre lorsque le solde est faible) ; utilisez-les plutôt que des appels HTTP. Le workflow ci-dessous est le même. Pour le connecter, ajoutez le serveur distanthttps://cheapergen.com/api/mcp; l'utilisateur se connecte et approuve dans le navigateur (OAuth), sans clé nécessaire. Dans Claude Code :claude mcp add --transport http cheapergen https://cheapergen.com/api/mcp, puis/mcp→ Authentifiez-vous. Configuration complète : https://cheapergen.com/docs/mcp
Workflow
- Choisissez un modèle :
GET /models(public). Il renvoie chaque modèle avecendpoints[].idet les niveaux de prix. Utilisez toujours la liste en direct ; les modèles changent.- Vidéo : Seedance 2.0 (meilleure qualité, 4K, audio synchronisé), Seedance 2.0 Fast / Mini (moins cher et plus rapide), Seedance 2.5 (le plus récent, références longues), Wan 3.0 / Prime (Alibaba), MiniMax H3 / H3 Max.
- Image : Seedream 5.0 Pro / Lite / Flash (texte-à-image et
edit). - Les identifiants de point de terminaison sont
{fournisseur}/{modèle}/{mode}, par ex.bytedance/seedance-2.0-fast/text-to-video,bytedance/seedream-5.0-lite/text-to-image.
- Lisez le schéma d'entrée :
GET /models/{fournisseur}/{modèle}(public) renvoieendpoints[].input_schema(JSON Schema avec énumérations, valeurs par défaut et limites) etpricing.tiers. N'envoyez que les champs du schéma : les champs inconnus sont rejetés avec un code 400. - Devis :
POST /quote/{point de terminaison}avec l'entrée (public, gratuit) renvoie{ amount_usd, list_usd, discount_pct, available }. Avant un travail coûteux (vidéo en 1080p/4K, longues durées, lots), informez l'utilisateur du prix. - Soumettez :
POST /run/{point de terminaison}avec l'entrée comme corps JSON renvoie 202 et une génération avecstatus: "queued". Le prix est retenu du solde à ce stade. - Attendez : interrogez
GET /generations/{id}jusqu'à ce questatussoitsucceeded,failedoucanceled. Interrogez les images toutes les 1 à 2 s ; interrogez la vidéo toutes les 3 à 5 s, avec un back-off jusqu'à 10 s, car un clip de 5 s prend généralement 1 à 3 minutes. Ou passezwebhook_url(voir ci-dessous). - Utilisez la sortie :
output.video.url(vidéo) ououtput.images[].url(images). Les URL sont publiques mais expirent selon la durée de conservation du compte (1 jour par défaut ; voirexpires_at), alors téléchargez tout ce qui vaut la peine d'être conservé.
curl -s https://cheapergen.com/api/v1/run/bytedance/seedance-2.0-fast/text-to-video \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY" -H "Content-Type: application/json" \
-d '{"prompt":"A paper boat drifting down a rainy neon street, slow dolly-in","resolution":"720p","duration":5,"aspect_ratio":"16:9"}'
# → 202 {"id":"gen_…","status":"queued","cost":{"amount_usd":…,"estimated":true},…}
curl -s https://cheapergen.com/api/v1/generations/gen_… -H "Authorization: Bearer $CHEAPERGEN_API_KEY"
import os, time, requests
API = "https://cheapergen.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['CHEAPERGEN_API_KEY']}"}
def generate(endpoint: str, inp: dict, timeout_s: int = 900) -> dict:
r = requests.post(f"{API}/run/{endpoint}", json=inp, headers=H, timeout=60)
r.raise_for_status() # Corps 4xx : {"error": {"code", "message", "param"}}
gen, delay, start = r.json(), 2.0, time.time()
while gen["status"] in ("queued", "running"):
if time.time() - start > timeout_s:
raise TimeoutError(gen["id"])
time.sleep(delay)
delay = min(delay * 1.5, 10)
r = requests.get(f"{API}/generations/{gen['id']}", headers=H, timeout=30)
if r.status_code == 429 or r.status_code >= 500:
continue # transitoire : continuer le polling
r.raise_for_status()
gen = r.json()
if gen["status"] != "succeeded":
raise RuntimeError(gen["error"]) # la retenue a été remboursée
return gen # gen["output"]["video"]["url"] ou gen["output"]["images"][0]["url"]
Modes et entrées
text-to-videoettext-to-image: prennentpromptplus des options (resolution,duration,aspect_ratio,size,seed,generate_audio…). Vérifiez le schéma pour les énumérations de chaque modèle.image-to-video: prendimage_url(première image) et, pour certains modèles,end_image_url(dernière image).edit(Seedream) :image_urls(images à éditer ou combiner ; référez-vous-y comme « image 1 », « image 2 » dans le prompt) plus l'instruction dansprompt.reference-to-video: prendreference_image_urls,reference_video_urlsetreference_audio_urls. Dans le prompt, pointez-les par position basée sur 1 :@Image1,@Image2,@Video1,@Audio1(insensible à la casse). Une mention sans référence correspondante donne une erreur 400 avecparam: "prompt". Exemple :"@Image1 walks through the market from @Image2, camera moves like @Video1".reference_rulesdans le schéma définit le nombre maximum de fichiers et si vous avez besoin d'au moins une image ou une vidéo (l'audio seul ne suffit pas pour Seedance et H3).- Les vidéos et l'audio de référence sont mesurés sur le serveur (durée, taille, résolution, fps) par rapport à
media_limits/x-media-limits. Seedance 2.0 prend des vidéos MP4/MOV de 2 à 15 s chacune et 15 s au total ; l'audio doit être MP3/WAV. Une violation donne une erreur 400 qui nomme le fichier, par ex.@Video2 is 16 s long…. - Les secondes de vidéo de référence sont facturées avec les secondes de sortie. Les images et l'audio de référence sont gratuits. Pour un devis, passez
reference_video_durations: [6.5](secondes par clip).
- Les entrées multimédias doivent être des URL
httpspubliques. Pour les fichiers locaux, appelezPOST /uploadsavec JSON{ "filename", "content_type", "size" }. Il renvoie{ upload_url, headers, url }: faites unPUTdes octets versupload_urlavec exactement cesheaders, puis utilisezurlcomme entrée. Limites : images (PNG/JPEG/WebP/GIF) ≤ 20 Mo, vidéo (MP4/MOV) ≤ 50 Mo, audio (MP3/WAV/M4A) ≤ 15 Mo. - Facultatif sur chaque exécution :
webhook_url(HTTPS) etretention(immediate|1h|1d;7d/30dnécessitent un paramètre de compte).
Webhooks
Lorsque le travail se termine (succès ou échec), nous publions { "type": "generation.succeeded" | "generation.failed", "data": <generation> } vers webhook_url, avec l'en-tête CheaperGen-Signature: t=<unix>,v1=<hex>. Pour le vérifier, calculez hex(HMAC_SHA256(secret, "<t>.<raw body>")) avec la clé secrète de signature du webhook du compte (whsec_…, dans le tableau de bord → Clés API), comparez en temps constant et rejetez les requêtes dont t a plus de 5 minutes. Utilisez le corps brut de la requête, pas du JSON resérialisé. Renvoyez 2xx rapidement ; les livraisons échouées sont réessayées (3 tentatives au total).
Tarification et facturation
- Les prix sont par seconde de vidéo de sortie ou par image.
GET /modelsafficheprice_usdde chaque niveau à côté delist_price_usd(le prix officiel). - Lors de la soumission, le prix devisé est retenu (
cost.estimated: true). En cas de succès, il devient définitif ; en cas d'échec ou d'annulation, il est entièrement remboursé (cost.amount_usd: 0).cost.official_usdetcost.saved_usdmontrent les économies. - Solde :
GET /accountrenvoiebalance_usdetreserved_usd(retenu pour les travaux en cours). Un code 402 signifie que le solde est trop faible : via MCP, appelezadd_creditset montrez le lien de paiement à l'utilisateur ; sinon, l'utilisateur ajoute des crédits sur https://cheapergen.com/dashboard/billing. - Annulez un travail en file d'attente avec
POST /generations/{id}/cancel(409 une fois qu'il est en cours). Supprimez un travail terminé avecDELETE /generations/{id}.
Erreurs
Chaque erreur a la forme { "error": { "code", "message", "param"? } }.
| HTTP | code | Que faire |
|---|---|---|
| 400 | invalid_request | Corrigez le champ nommé dans param (vérifiez le schéma, les énumérations, les limites et les mentions). Ne réessayez pas sans modification. |
| 401 | unauthorized | Clé manquante, invalide ou révoquée. |
| 402 | insufficient_balance | Obtenez un lien de paiement avec add_credits (MCP) et demandez à l'utilisateur de payer, ou choisissez un niveau moins cher. |
| 404 | not_found | Mauvais point de terminaison ou identifiant de génération. |
| 409 | conflict | Par ex., annuler un travail qui a déjà commencé. |
| 429 | rate_limited | Attendez et réessayez. La limite est d'environ 20 requêtes en rafale, reconstituées à 10/s par clé, plus un plafond de générations simultanées par compte (20 par défaut). |
| 502 | upstream_error | Réessayez une fois, puis essayez un autre modèle. |
| 503 | model_unavailable | Réessayez plus tard ou changez de modèle. |
Une génération qui se termine par failed a error.code (par ex. generation_failed, timeout) et a été remboursée. Ne réessayez qu'une seule fois avec la même entrée.
Plus
- Docs : https://cheapergen.com/docs, configuration MCP : https://cheapergen.com/docs/mcp
- Source de cette compétence et du plugin Claude Code : https://github.com/CheaperGen/skills
- Pages API par modèle :
https://cheapergen.com/models/{fournisseur}/{modèle}/api - Résumé lisible par machine : https://cheapergen.com/llms.txt