Guías
Generaciones
Cómo funcionan las generaciones asíncronas: estados queued, running, succeeded, failed y canceled; buenas prácticas para consultar el estado, gestionar los resultados y cancelar.
Los modelos de video e imagen tardan desde unos segundos hasta varios minutos, por lo que las solicitudes son asíncronas. Al enviar una solicitud, recibes de inmediato una generación; luego puedes consultar su estado o recibir un webhook cuando alcance un estado final. Un objeto de generación describe la tarea completa: entrada, estado, resultado, error y coste.
Ciclo de vida#
queued si ninguna capacidad la acepta. Las tareas fallidas y canceladas se reembolsan íntegramente.| Estado | ¿Es final? | Significado |
|---|---|---|
queued | No | Aceptada, aún sin empezar: espera en la cola de tu cuenta (si superas tu límite de concurrencia) o a que haya capacidad. El precio está reservado en tu saldo. Aún puedes cancelarla. |
running | No | El modelo está generando el resultado. Se establece started_at. Ya no se puede cancelar. |
succeeded | Sí | Terminada. output contiene las URL de los archivos multimedia y el importe reservado pasa a ser el cargo final. |
failed | Sí | No se pudo completar. error explica el motivo y se reembolsó todo el importe reservado. |
canceled | Sí | La cancelaste mientras estaba en cola. Se reembolsó todo el importe reservado. |
succeeded, failed y canceled son estados finales: la generación no cambia después de alcanzar uno de ellos. Trata cualquier otro valor como «aún en curso» para que tu código siga funcionando si añadimos estados intermedios.
1. Enviar#
POST /api/v1/run/{endpoint} con las entradas del modelo en el cuerpo JSON. El ID del endpoint combina el modelo y la tarea; por ejemplo, bytedance/seedance-2.0-fast/text-to-video. Consulta la página de Modelos para ver todos los endpoints y sus campos.
Validamos la entrada, calculamos el precio, lo reservamos de tu saldo y ponemos la tarea en cola. La respuesta es 202 Accepted con la generación, además de urls.get y urls.cancel para mayor comodidad:
{
"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 lento hacia un ceramista que da forma a un jarrón a la hora dorada; polvo en la luz y poca profundidad de campo",
"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"
}
}Imágenes, videos y audios de referencia#
Las modalidades reference-to-video admiten hasta tres tipos de referencias, cada uno como una lista de URL HTTPS (enlaces públicos o URL de uploads): reference_image_urls para personajes, productos y escenas; reference_video_urls para movimiento, movimientos de cámara y efectos; y reference_audio_urls para voz, música y sonido.
Menciónalas en el prompt por posición: @Image1 es la primera URL de reference_image_urls, @Video1 la primera de reference_video_urls, @Audio2 el segundo clip de audio, etc. Las menciones no distinguen mayúsculas y se normalizan como @Image1. Si una mención no tiene una referencia correspondiente (por ejemplo, @Video2 con un solo video adjunto), se rechaza con 400 invalid_request (param: "prompt") antes de cobrar nada.
{
"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
}Al enviar la solicitud, descargamos el inicio de cada video y archivo de audio de referencia y comprobamos su duración, tamaño, resolución y frecuencia de fotogramas reales frente a los límites del modelo. Si un archivo no cumple los límites —por ejemplo, un clip de 20 segundos, un video de 1080p para un modelo que admite 720p, un M4A cuando se requiere MP3 o WAV, o una URL que no responde—, devolvemos 400 invalid_request con param indicando el campo (por ejemplo, reference_video_urls) y un mensaje que identifica el clip, sin cobrar nada. Los videos de referencia añaden segundos facturables; consulta Facturación.
| Modelo | Imágenes | Videos | Audio | Reglas |
|---|---|---|---|---|
| Seedance 2.0 | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s cada uno, 15 s en total · ≤ 50 MB en total · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | ≤ 12 archivos en total; requiere una imagen o un video |
| Seedance 2.5 | ≤ 30 | ≤ 10 · MP4/MOV · 2–30 s cada uno, 30 s en total · ≤ 200 MB cada uno · 24–60 fps | ≤ 10 · MP3/WAV · 2–30 s cada uno, 30 s en total · ≤ 15 MB cada uno | ≤ 50 archivos en total; requiere al menos una referencia |
| Seedance 2.0 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s cada uno, 15 s en total · ≤ 50 MB en total · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | ≤ 12 archivos en total; requiere una imagen o un video |
| Seedance 2.0 Mini | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s cada uno, 15 s en total · ≤ 50 MB en total · Solo 480p–720p · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | ≤ 12 archivos en total; requiere una imagen o un video |
| Wan 3.0 | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s cada uno, 15 s en total · ≤ 100 MB cada uno · 16+ fps · referencia + salida ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | requiere al menos una referencia |
| Wan 3.0 Prime | ≤ 4 | ≤ 5 · MP4/MOV · 1–15 s cada uno, 15 s en total · ≤ 100 MB cada uno · 16+ fps · referencia + salida ≤ 30 s | ≤ 5 · MP3/WAV · 1–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | requiere al menos una referencia |
| MiniMax H3 | ≤ 5 | ≤ 3 · MP4/MOV · 2–15 s cada uno, 15 s en total · ≤ 50 MB cada uno · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | ≤ 12 archivos en total; requiere una imagen o un video |
| MiniMax H3 Fast | ≤ 9 | ≤ 3 · MP4/MOV · 2–15 s cada uno, 15 s en total · ≤ 50 MB cada uno · 24–60 fps | ≤ 3 · MP3/WAV · 2–15 s cada uno, 15 s en total · ≤ 15 MB cada uno | ≤ 15 archivos en total; requiere una imagen o un video |
Los videos deben ser archivos MP4/MOV con H.264 o H.265. Se aplican los límites más estrictos de la capacidad que usa cada modelo, por lo que el servicio del modelo acepta cualquier solicitud que supere esta comprobación. Las imágenes y el audio de referencia no modifican el precio.
2. Consultar el resultado#
GET /api/v1/generations/{id} devuelve el estado actual. Consultar una generación también hace avanzar el proceso: si corresponde comprobar el estado, lo hacemos antes de responder; por eso, los datos de una consulta nunca tienen más de unos segundos.
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}`);
}Intervalos de consulta recomendados#
- Imágenes: cada 1–2 segundos. La mayoría termina en menos de 30 segundos.
- Videos: cada 3–5 segundos al principio; después, amplía gradualmente el intervalo hasta 10 segundos. Un clip de 5 segundos suele tardar entre uno y tres minutos; las resoluciones altas tardan más.
- Las consultas cuentan para el límite de solicitudes. Si ejecutas muchas tareas a la vez, es preferible usar webhooks.
3. Usa el resultado#
Si la tarea termina correctamente, output contiene URL HTTPS a los archivos multimedia generados. Los modelos de video devuelven un archivo:
{
"output": {
"video": {
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.mp4",
"content_type": "video/mp4"
}
}
}Los modelos de imagen devuelven una lista, con una entrada por cada imagen generada:
{
"output": {
"images": [
{
"url": "https://cdn.cheapergen.com/outputs/gen_8c2QmX1nq0k4Lw7Z.png",
"content_type": "image/png"
}
]
}
}Guarda los resultados que quieras conservar
Las URL de salida se sirven desde nuestra CDN hasta que caduca el contenido de la generación: de forma predeterminada, un día después de finalizar las generaciones de la API (consulta Retención de datos). Cuando una tarea termine, copia los resultados que quieras conservar a tu propio almacenamiento.Fallos y reembolsos#
Si una generación falla, status es failed, error indica el motivo y qué hacer, y cost.amount_usd pasa a 0: se devuelve a tu saldo todo el importe retenido. Los trabajos se reintentan automáticamente en todas las demás rutas disponibles antes de marcarlos como fallidos, si se trata de una interrupción o un error del proveedor. No se reintentan si los rechaza el filtro de seguridad o si el modelo no admite una entrada: volverían a rechazarse por el mismo motivo. Cuando un proveedor no puede descargar uno de tus archivos de entrada, normalmente lo descargamos nosotros y volvemos a intentarlo con nuestra copia, al mismo precio; input_unreachable suele significar que no se pudo descargar en absoluto.
{
"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": "Tu solicitud no superó la revisión de seguridad del contenido. Ajusta el prompt y vuelve a intentarlo."
},
"cost": {
"amount_usd": 0,
"currency": "usd",
"estimated": false
}
}code: la categoría general, sin cambios desde el lanzamiento:generation_failed(se rechazó la entrada o no se pudo completar),upstream_error,timeoutomodel_unavailable.reason: el motivo exacto, según la tabla siguiente. Usa este valor en las integraciones nuevas; pueden añadirse otros motivos.message: explicación en lenguaje claro de lo ocurrido, apta para mostrar a tus usuarios. Si lo rechaza un filtro de seguridad, identifica al responsable (el proveedor del modelo).hint: qué cambiar o hacer a continuación.retryable:truesi al volver a enviar la misma solicitud puede funcionar;falsesi volvería a fallar por el mismo motivo.refunded:truecuando se devuelve el importe reservado. Las generaciones fallidas nunca se cobran.param: el campo de entrada que hay que cambiar, si podemos identificarlo (por ejemplo,image_urloduration).detail: el texto original del proveedor del modelo, si aporta información adicional.
| error.reason | error.code | Qué ocurrió | Qué hacer | ¿Reenviar sin cambios? |
|---|---|---|---|---|
content_blocked | generation_failed | El filtro de seguridad del proveedor del modelo rechazó el prompt, un archivo de entrada o el resultado generado (por ejemplo, por un personaje con derechos de autor, una persona real o contenido explícito). El mensaje indica de quién era el filtro. | Reformula el prompt (describe el aspecto en vez de mencionar a un personaje, una marca o una persona real), usa otros archivos de entrada o prueba un modelo de otro proveedor. Si lo envías sin cambios, volverá a fallar por el mismo motivo. | No; primero haz un cambio |
invalid_input | generation_failed | El modelo no pudo aceptar una de las entradas o los ajustes: un archivo demasiado grande, en un formato no admitido, con dimensiones o relación de aspecto incorrectas, demasiado largo o con un valor no compatible. param indica el campo cuando podemos identificarlo. | Corrige el campo indicado (consulta los límites del modelo en su página de API) y vuelve a enviar la solicitud, o prueba otro modelo. | No; primero haz un cambio |
input_unreachable | generation_failed | No se pudo descargar una URL de entrada: requiere iniciar sesión, el enlace firmado ha caducado, no apunta directamente al archivo o el servidor de origen rechazó la solicitud. Cuando el proveedor del modelo no puede descargar un archivo, normalmente lo descargamos nosotros y volvemos a intentarlo con nuestra copia; por eso, este mensaje suele significar que no se pudo descargar el archivo en absoluto. | Usa una URL pública y directa al archivo (o súbelo con POST /api/v1/uploads) y vuelve a enviar la solicitud. | No; primero haz un cambio |
upstream_unavailable | upstream_error | El proveedor del modelo estaba caído, sobrecargado o sin capacidad, y probamos todas las rutas disponibles. | Vuelve a intentarlo en uno o dos minutos o usa otro modelo. | Sí |
upstream_error | upstream_error | El proveedor encontró un error interno durante la generación, después de que probáramos todas las rutas disponibles. | Vuelve a intentarlo; estos errores suelen ser temporales. Si sigue fallando, prueba otro modelo. | Sí |
timeout | timeout | La generación no terminó a tiempo (por el límite del proveedor o por nuestro límite de 40 minutos). | Vuelve a intentarlo. Los clips más cortos o de menor resolución terminan antes. | Sí |
output_unavailable | upstream_error | El modelo terminó, pero no devolvió ningún archivo utilizable o no se pudo descargar y guardar el resultado. | Retry. | Sí |
model_unavailable | model_unavailable | El modelo o esta modalidad dejó de estar disponible mientras se procesaba la generación. | Elige otro modelo o vuelve a intentarlo más tarde. | No; primero haz un cambio |
canceled | upstream_error | El proveedor canceló la tarea o hizo que caducara antes de terminar. (Si cancelas tú la generación, su estado es canceled y no se informa de ningún error.) | Retry. | Sí |
generation_failed | generation_failed | El modelo se detuvo sin generar un resultado ni indicar el motivo. | Vuelve a intentarlo una vez; si vuelve a fallar, simplifica el prompt o las entradas, o prueba otro modelo. | Sí |
Las generaciones que fallaron antes de que existiera reason conservan el code original; también se rellenan reason y hint.
Precio de emergencia#
Si la capacidad habitual de una solicitud no está disponible, puede ejecutarse con capacidad de mayor costo al precio de emergencia, que nunca supera el precio oficial del modelo. allow_fallback_price determina el comportamiento y, en la API REST y MCP, el valor predeterminado es true para nuevas solicitudes: se cotiza y cobra el precio de emergencia. Si falla a mitad de camino la capacidad de un trabajo que ya se aceptó al precio estándar, puede cambiarse a esa otra capacidad (el importe adicional se reserva en ese momento). max_cost_usd establece un límite para ambos importes. Envía allow_fallback_price: false para no pagar nunca más que el precio cotizado (en un Plan Pro o Max; de lo contrario, un trabajo aceptado también puede subir, como máximo, hasta el precio estándar): las nuevas solicitudes reciben 503 fallback_price_declinedy, si falla un trabajo aceptado, se reembolsará. Los trabajos de Studio nunca pasan a un precio superior después de que haces clic. Cuando se aplica, el pricing.fallback (también en los webhooks) lo indica junto con ambos precios.
Verificador de seguridad#
enable_safety_checker tiene el valor predeterminado true. Puedes enviar false mediante la API; en Studio y en las páginas de los modelos está siempre activado. Su función depende del modelo:
- Modelos cerrados (Seedance, Kling, Veo, MiniMax H3, Wan 3.0…) incluyen la moderación propia de sus laboratorios, que nadie puede desactivar. Aceptan
trueyfalse, y ninguno de los dos cambia nada, así que la opción no aparece en sus esquemas. MiniMax H3 Max es la excepción: permite desactivar el filtro, por lo que incluye esa opción en su esquema. Esas solicitudes utilizan su propia configuración de seguridad — posiblemente al precio de emergencia, pero nunca por encima del precio oficial. - Seedream 4.5 and Seedream 5.0 Lite también lo incluyen. Si se desactiva, la solicitud se ejecuta con la configuración internacional propia del modelo de ByteDance; esa configuración no aplica ningún filtro adicional; si está activado, se aplican los filtros habituales. Nuestro filtro sigue bloqueando cualquier contenido sexual que involucre a menores. Las solicitudes con esta opción desactivada tienen un precio propio más alto: Seedream 4.5 $0.04 per image · Seedream 5.0 Lite $0.035 per image.
/quotelo devuelve cuando envíasenable_safety_checker: false(confallback.reason"safety_checker_off"). Cuenta como una precio de emergencia: conallow_fallback_price: falsese rechaza una solicitud así. Si no se puede ejecutar en ese momento, la solicitud se rechaza con503 model_unavailable(param: "enable_safety_checker"); envíatruepara ejecutarla con el filtro estándar. - Modelos de pesos abiertos los incluye. Cuando una generación se ejecuta en una capacidad sin filtro propio, nuestro verificador revisa primero el prompt y las imágenes de entrada: con el interruptor activado, bloquea el contenido sexual, la violencia gráfica y el contenido de autolesión; desactivado, sigue bloqueando cualquier contenido sexual que involucre a menores. Cuando la capacidad tiene un filtro propio que se puede activar o desactivar, el interruptor se le pasa tal como lo enviaste; desactivado, nuestro verificador sigue bloqueando cualquier contenido sexual que involucre a menores.
false en un modo que no enumera la opción (y no puede desactivar su verificador) devuelve 400 invalid_request. Desactivarla no permite ningún contenido que prohíba nuestra Política de uso aceptable.
Retención de datos#
Generaciones de API se conservan durante 1 día de forma predeterminada, a partir del momento en que termina la generación. Después, eliminamos automáticamente el prompt, los archivos multimedia de entrada, los resultados y sus archivos. La generación se conserva con su modelo, los parámetros que determinan el precio, el coste y las marcas de tiempo, para que el historial de uso y las facturas sigan siendo precisos: output pasa a ser null, se establece purged_at y content_expired explica el motivo. Descarga los resultados que quieras conservar antes de expires_at.
retention | Se elimina el contenido |
|---|---|
immediate | 10 minutos después de entregar el resultado —cuando se acepta tu webhook o consultas la generación terminada con GET— para que todavía puedas descargar los archivos. Como máximo, 1 hora después de terminar. |
1h | Una hora después de que termine. |
1d | Un día después de que termine. Es el valor predeterminado. |
7d, 30d | Siete o 30 días después de que termine. Solo para cuentas Enterprise. |
Envía retention en el cuerpo de la solicitud para elegir el plazo de cada generación. Cualquier cuenta puede acortarlo (o solicitar hasta 1d); 7d y 30d requieren un ajuste de retención a nivel de cuenta: contactar con ventas. Si solicitas un plazo superior al permitido en tu cuenta, se devuelve 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"
}Generaciones de Studio y del entorno de prueba se conservan hasta que los elimines. Las Cargas se conservan mientras alguna generación guardada las use; los archivos que no use ninguna generación se eliminan después de 1 día. Al eliminar tu cuenta, se eliminan todas tus generaciones y archivos. Cuando el proveedor del modelo permite elegir, también le pedimos que conserve lo mínimo posible.
Eliminar una generación#
Elimina cualquier generación terminada con DELETE /api/v1/generations/{id}, desde la lista de generaciones del panel o desde el visor de Studio; con la API, también una en cola mientras aún se pueda cancelar (primero se cancela y lo reservado se reembolsa íntegramente). Sus archivos, prompt y entradas se eliminan al momento y desaparece de las listas; el cargo permanece en tu historial de facturación. Consulta la referencia de la API.
Cancelación#
POST /api/v1/generations/{id}/cancel cancela una generación que aún está queued y reembolsa el importe reservado. Cuando una tarea está running, el modelo ya está procesándola; cancelarla devuelve 409 conflict, pero la tarea termina y se factura con normalidad. Algunos modelos no permiten cancelar tareas una vez en cola; en esos casos también se devuelve 409.
curl -X POST https://cheapergen.com/api/v1/generations/gen_8c2QmX1nq0k4Lw7Z/cancel \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Listar generaciones#
GET /api/v1/generations muestra tus generaciones, de la más reciente a la más antigua, con paginación por cursor. Filtra por status, model o source (playground, api, mcp); pasa el next_cursor devuelto como cursor para obtener la página siguiente. Consulta los detalles en referencia de la API.
curl "https://cheapergen.com/api/v1/generations?status=succeeded&limit=50" \
-H "Authorization: Bearer $CHEAPERGEN_API_KEY"Las generaciones de Studio y del entorno de prueba de las páginas de modelos también aparecen aquí, con source: "playground"; las solicitudes de la API tienen source: "api".
¿Algo no está claro o falta información? Escribe a support@cheapergen.com; leemos todos los mensajes.