API de Seedance 2.5: crea y descarga videos con Python
Usa la API de Seedance 2.5 en Affogato: sube una foto, estima créditos, crea una generación y descarga el video con Python.

El flujo completo: de tu clave API al video
Affogato admite fotos de personas reales en su flujo de Seedance 2.5. Si otro proveedor bloquea una imagen por contener un rostro, esta opción permite construir la escena alrededor de la persona que necesita tu aplicación. Consulta siempre los requisitos del modelo y usa imágenes autorizadas.
Este tutorial recorre el proceso completo: seleccionar el modelo, subir una foto, estimar los créditos, enviar una sola generación, consultar su estado y descargar el archivo. Conservamos los comandos y el prompt del ejemplo probado en inglés para que puedas reproducir la misma solicitud.
Usamos a Noor, un personaje ficticio. La solicitud envió únicamente su foto en la calle; la foto con el perro muestra otra vista del personaje, pero no se utilizó como entrada en este trabajo.


La prueba del 10 de noviembre de 2026 produjo un video de 6,08 segundos a 720 × 1280, con audio. Se cobraron 515 créditos y transcurrieron 2 minutos y 29 segundos entre creación y finalización. Son medidas de esa solicitud, no una promesa de precio o velocidad para todas las generaciones.
1. Prepara tu clave API
Abre Developers en Affogato y crea una clave para el espacio de trabajo cuyos créditos quieres utilizar. Guárdala en la variable de entorno AFFOGATO_API_KEY y léela desde tu proceso de Python. No la incluyas en el JavaScript público de una página ni en un archivo que vayas a publicar.
La base de la API pública es https://api.affogato.ai/v1. Las solicitudes se autentican con Authorization: Bearer. Esta interfaz es distinta de los endpoints internos de la aplicación web. Tener una clave válida y disponer de créditos suficientes son requisitos separados.
python -m pip install requests
# Replace the placeholder with your API key on your server.
export AFFOGATO_API_KEY="YOUR_API_KEY"
# The example below never prints or stores the key.2. Consulta el modelo y sus entradas
Recupera los detalles del modelo antes de preparar el cuerpo de la solicitud. El identificador, las entradas y los parámetros devueltos definen qué admite ese endpoint. No supongas que los campos de un modelo de primer fotograma funcionan igual en uno de referencia.
curl --fail-with-body \
"https://api.affogato.ai/v1/models/seedance-2-5-ref2v-modelark" \
-H "Authorization: Bearer $AFFOGATO_API_KEY"El ejemplo utiliza seedance-2-5-ref2v-modelark y una entrada reference_image de un solo archivo. No incluye video de referencia. Comprueba siempre las duraciones, resoluciones y proporciones disponibles antes de modificar los ajustes.
3. Sube la fotografía y prepara la solicitud
Sube la foto mediante el endpoint público de archivos. Guarda el identificador devuelto y colócalo en reference_image. Sube cada archivo por separado y combina identificadores solo cuando el esquema indique que admite varias entradas.
curl --fail-with-body \
"https://api.affogato.ai/v1/files" \
-H "Authorization: Bearer $AFFOGATO_API_KEY" \
-F "file=@noor-street.webp;type=image/webp" \
-o uploaded-file.json{
"id": "e5e7368f-7c43-4860-a337-e6c64a43b6df",
"mime_type": "image/webp"
}Guarda el siguiente cuerpo como request.json y sustituye YOUR_UPLOADED_FILE_ID por el identificador de tu archivo. Contiene el prompt exacto de la prueba y sus ajustes: seis segundos, 720p, 9:16 y audio.
{
"model": "seedance-2-5-ref2v-modelark",
"input": {
"reference_image": "YOUR_UPLOADED_FILE_ID",
"prompt": "Create a new six-second video starring Noor, the adult woman in #Image1. Use the photo only for her identity: preserve her face, curly updo, loose face-framing curls and hoop earrings. Compose a new scene, not the street photograph. Noor wears a floor-length satin evening gown at a black-tie reception. She walks toward the camera, pauses beside a tall floral arrangement and smiles at someone just beside the camera. Guests in tuxedos and evening dresses converse behind her. One continuous shot, camera moving gently backward, her face clearly visible. Quiet reception ambience, no distinct dialogue, music, text or overlays.",
"duration": 6,
"resolution": "720p",
"aspect_ratio": "9:16",
"generate_audio": true
}
}4. Estima el coste y envía una sola generación
POST /v1/generations/estimate permite conocer los créditos estimados sin crear el video. Estima la misma solicitud que vas a enviar: si cambias la duración u otro ajuste con precio, consulta de nuevo la estimación.
curl --fail-with-body \
"https://api.affogato.ai/v1/generations/estimate" \
-H "Authorization: Bearer $AFFOGATO_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @request.json{
"object": "estimate",
"model": "seedance-2-5-ref2v-modelark",
"credits": 515
}Puedes descargar complete_loop.py y la foto noor-street.webp en la misma carpeta. El script consulta el modelo, sube la imagen, prepara la solicitud y estima el coste. Por defecto no genera nada; --submit crea el trabajo de pago. El límite de 1.000 créditos es una protección del ejemplo, no el precio anunciado del modelo.
Descargar el ejemplo completo de Python.
Descargar la foto de entrada de Noor.
# Upload the photo and estimate first; no generation is created.
python complete_loop.py --photo noor-street.webp
# Generate, poll, and download output.mp4.
python complete_loop.py --photo noor-street.webp --submit --max-credits 1000
# If interrupted, run the same command again with the same state file.
# It resumes the existing job rather than creating another one.# Generate this value once per new job; keep it for retries.
JOB_KEY="$(python -c 'import uuid; print(uuid.uuid4())')"
curl --fail-with-body \
"https://api.affogato.ai/v1/generations" \
-H "Authorization: Bearer $AFFOGATO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $JOB_KEY" \
--data-binary @request.json \
-o generation.jsonGuarda el identificador de generación y la misma Idempotency-Key. Si la conexión se corta y no sabes si el servidor aceptó la solicitud, no generes una clave nueva: conserva la solicitud y la clave originales. Una clave nueva puede crear otro trabajo de pago. No reutilices la misma clave para un prompt diferente.
{
"id": "b89d784d-97fc-46ff-a38c-240caad08cd4",
"status": "queued",
"model": "seedance-2-5-ref2v-modelark",
"outputs": [],
"credits_charged": 515
}5. Consulta el estado y descarga el resultado
Consulta GET /v1/generations/{id} usando el identificador recibido. Los estados queued y processing indican que el trabajo sigue en curso. Los estados succeeded, failed y cancelled indican que terminó.
GENERATION_ID="YOUR_GENERATION_ID"
curl --fail-with-body \
"https://api.affogato.ai/v1/generations/$GENERATION_ID?wait=25" \
-H "Authorization: Bearer $AFFOGATO_API_KEY" \
-o result.jsonQue tu programa deje de esperar no significa que la generación haya fallado. Guarda el estado y vuelve a consultar el trabajo existente. El script conserva api-example-state.json para poder reanudarlo y guarda el primer video listo como output.mp4.
{
"id": "b89d784d-97fc-46ff-a38c-240caad08cd4",
"status": "succeeded",
"model": "seedance-2-5-ref2v-modelark",
"credits_charged": 515,
"credits_refunded": 0,
"created_at": "2026-11-10T00:27:44.086720+00:00",
"completed_at": "2026-11-10T00:30:12.935173+00:00",
"outputs": [
{
"id": "a660b8b9-6f0f-488f-b0d6-662ca7f101af",
"status": "ready",
"mime_type": "video/mp4",
"duration_ms": 6080,
"url": "<output download URL from your response>"
}
]
}Cuando el estado sea succeeded, busca una salida de video lista y descarga su URL. No envíes la clave API al servidor de descarga. El ejemplo siguiente guarda el archivo sin reenviar el encabezado Authorization.
# Run only after result.json says succeeded and outputs contain a ready video.
python - <<'PYTHON'
import json, requests
from pathlib import Path
job = json.loads(Path("result.json").read_text())
assert job["status"] == "succeeded", job["status"]
video = next(o for o in job["outputs"]
if o["status"] == "ready" and o.get("url")
and (o.get("mime_type") or "").startswith("video/"))
# No API Authorization header is sent to the download URL.
r = requests.get(video["url"], timeout=60)
r.raise_for_status()
Path("output.mp4").write_bytes(r.content)
print("Saved output.mp4")
PYTHONAbre output.mp4 en un reproductor y comprueba el contenido completo. La copia web que aparece al principio de este artículo está comprimida para facilitar la reproducción.
6. Gestiona los errores y revisa el video
Un error de autenticación requiere revisar la clave; un saldo insuficiente, el espacio de trabajo; una entrada inválida, el archivo o el esquema. Para límites de frecuencia, respeta las indicaciones de reintento del servidor. No conviertas cualquier error en una nueva generación automática.
Antes de integrar el resultado en tu producto, revisa la identidad, las manos, el movimiento y el audio. Después, guarda las claves en el servidor, conserva los identificadores de trabajo y muestra al usuario un estado de progreso claro. La documentación de la API sigue siendo la referencia para el contrato completo.
Versión en español del artículo original en inglés, con los mismos resultados y archivos del ejemplo.