Generación de vídeo

POST /v1/videos · GET /v1/videos/{id} · DELETE /v1/videos/{id}

Genera vídeos cortos a partir de un prompt de texto, opcionalmente guiados por fotogramas de referencia (primero/último). Es una API de jobs asíncronos con la forma estándar create + poll: POST /v1/videos crea una tarea que responde en ~2 segundos, la sondeas hasta que termina, y la cabecera Prefer: wait convierte las generaciones rápidas en una sola llamada síncrona. Modelos Seedance, una única clave de API, la misma facturación que el resto de endpoints.

ℹ

La API de vídeo está en preview limitada (pruebas por invitación). Los modelos aparecen en el catálogo y en los precios, pero crear tareas requiere que tu espacio de trabajo esté en la lista de permitidos - contáctanos para habilitarlo.

Endpoints y ciclo de vida de la tarea

Un recurso de tarea, cuatro operaciones. Una tarea pasa de queued → in_progress → un estado terminal: completed, failed o cancelled. La respuesta de creación incluye enlaces status_url / cancel_url listos para usar - nunca montas URLs a mano.

EndpointDescripción
POST /v1/videosCrea una tarea de generación. Responde en ~2 s con el objeto de tarea (status queued) y los enlaces de sondeo.
GET /v1/videos/{id}Sondea la tarea. En completed obtienes data[0].url, usage.completion_tokens y los parámetros realmente aplicados; en failed un error estructurado con el código y el mensaje del proveedor.
DELETE /v1/videos/{id}Cancela la tarea. Solo las tareas queued pueden cancelarse; una tarea cancelada nunca se factura.
GET /v1/videos/modelsLista los modelos de vídeo disponibles para tu clave, con las restricciones de resolución/duración y los precios de cada modelo.

Azúcar síncrono - Prefer: wait

Añade una cabecera Prefer: wait o Prefer: wait=N (N acotado a 1..60 segundos) a la llamada de creación y el gateway mantiene la petición abierta. Si la tarea termina dentro de la ventana, recibes directamente el objeto terminal - con URL del vídeo y usage, sin polling. Si no llega a tiempo, la llamada se degrada con elegancia: recibes el objeto de estado actual (sin error, la tarea sigue en marcha) y continúas con el polling normal.

Cuerpo de la solicitud

ParámetroTipoDescripción
model*stringEl modelo de vídeo a usar (p. ej. seedance-1-5-pro-251215). Lista todos los modelos disponibles vía GET /v1/videos/models.
prompt*stringDescripción en texto del vídeo deseado.
imagestring | string[]Entrada image-to-video: una imagen = primer fotograma, dos imágenes = primer + último fotograma. Cada entrada es un data URI o una URL https.
resolutionstringResolución de salida: 480p, 720p, 1080p o 4k. El conjunto soportado varía por modelo - ver la tabla de modelos.
ratiostringRelación de aspecto: 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 o adaptive.
durationintegerDuración del clip en segundos (rango por modelo dentro de 2..15). Algunos modelos también aceptan -1 para que el modelo elija.
seedintegerSeed opcional para salida reproducible (donde se soporte).
watermarkbooleanSi se renderiza la marca de agua del proveedor.
generate_audiobooleanGenerar pista de audio (true por defecto). En modelos con tarifa doble cambia el precio - ver la tabla de modelos.

Modelos disponibles

La disponibilidad de modelos depende de tu despliegue. Obtén la lista en vivo y consciente del cumplimiento - con las restricciones de resolución/duración y los precios de cada modelo - vía GET /v1/videos/models. La alineación actual:

ModeloResolucionesDuraciónPrecioNotas
dreamina-seedance-2-0-260128 480p · 720p · 1080p · 4k 4-15 s 480p/720p $7.0 · 1080p $7.7 · 4k $4.0 Buque insignia 2.0; hasta 4K
dreamina-seedance-2-0-fast-260128 480p · 720p 4-15 s $5.6 Variante 2.0 más rápida
dreamina-seedance-2-0-mini-260615 480p · 720p 4-15 s $3.5 Variante 2.0 más pequeña
seedance-1-5-pro-251215 480p · 720p · 1080p 4-12 s $2.4 audio · $1.2 muted Tarifa según generate_audio
seedance-1-0-pro-fast-251015 480p · 720p · 1080p 2-12 s $1.0 El más barato

Precio: USD por 1M de video tokens. seedance-1-5-pro-251215 factura $2.4 con la pista de audio activada (generate_audio: true, el valor por defecto) y $1.2 sin ella; el resto de modelos cobra una tarifa única por tramo de resolución.

Video tokens y precios

El vídeo se factura en video tokens, derivados de la salida real: tokens ≈ ancho × alto × 24 fps × segundos / 1024. Las tarifas son por 1M de video tokens y siguen los parámetros realmente aplicados (devueltos en la tarea completed) - así, ratio: "adaptive" y duration: -1 se facturan por lo que el modelo produjo realmente.

Referencias intuitivas en seedance-1-5-pro-251215 con audio: un clip 480p / 16:9 / 4 s ≈ 40,6K video tokens ≈ $0.10; uno de 720p / 5 s ≈ 108,9K tokens ≈ $0.26.

Facturación

Solo se factura en caso de éxito: el cargo ocurre una única vez, cuando la tarea alcanza completed por primera vez, según el usage de video tokens devuelto. Las tareas fallidas (incluidos los rechazos de moderación de contenido) y las canceladas nunca se facturan - el error del proveedor se transmite tal cual.

!

El data[0].url devuelto es una URL prefirmada del proveedor que caduca en ~24 horas - descárgalo pronto y realoja el archivo en tu propio almacenamiento si lo necesitas a largo plazo.

Ejemplo - curl, en un solo paso (Prefer: wait)

curl https://synthorai.io/v1/videos \
  -H "Authorization: Bearer $SYNTHORAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=60" \
  -d '{
    "model": "seedance-1-0-pro-fast-251015",
    "prompt": "A corgi puppy chasing a butterfly across a meadow, cinematic",
    "resolution": "480p",
    "ratio": "16:9",
    "duration": 4
  }'

# Finished inside the wait window → the terminal object comes straight back:
{
  "id": "vid_6091d8d1af805818b1470488",
  "object": "video",
  "model": "seedance-1-0-pro-fast-251015",
  "status": "completed",
  "data": [{ "url": "https://…tos….mp4?…" }],
  "usage": { "completion_tokens": 40594, "total_tokens": 40594 },
  "resolution": "480p", "ratio": "16:9", "duration": 4, "fps": 24,
  "seed": 34142
}
# Not done in time → the current status object is returned instead (no error,
# the task keeps running) - continue polling status_url as usual.

Ejemplo - curl, create + poll

# 1) Create - returns in ~2 s with a queued task object
curl https://synthorai.io/v1/videos \
  -H "Authorization: Bearer $SYNTHORAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-1-5-pro-251215",
    "prompt": "A corgi puppy chasing a butterfly across a meadow, cinematic",
    "resolution": "720p",
    "duration": 5,
    "generate_audio": true
  }'

{
  "id": "vid_6091d8d1af805818b1470488",
  "object": "video",
  "model": "seedance-1-5-pro-251215",
  "status": "queued",
  "created_at": 1784619862,
  "status_url": "https://synthorai.io/v1/videos/vid_6091d8d1af805818b1470488",
  "cancel_url": "https://synthorai.io/v1/videos/vid_6091d8d1af805818b1470488"
}

# 2) Poll until status is terminal (completed | failed | cancelled)
curl https://synthorai.io/v1/videos/vid_6091d8d1af805818b1470488 \
  -H "Authorization: Bearer $SYNTHORAI_API_KEY"

{
  "id": "vid_6091d8d1af805818b1470488",
  "object": "video",
  "model": "seedance-1-5-pro-251215",
  "status": "completed",
  "data": [{ "url": "https://…tos….mp4?…" }],
  "usage": { "completion_tokens": 108900, "total_tokens": 108900 },
  "resolution": "720p", "ratio": "16:9", "duration": 5, "fps": 24,
  "seed": 34142, "generate_audio": true
}

# 3) Download the video - the URL is pre-signed (no auth header) and expires
#    in ~24 h: fetch promptly and re-host if you need it long-term.
curl -o out.mp4 "https://…tos….mp4?…"

Ejemplo - Python (requests)

import time
import requests

BASE = "https://synthorai.io/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

task = requests.post(f"{BASE}/videos", headers=HEADERS, json={
    "model": "seedance-1-5-pro-251215",
    "prompt": "A corgi puppy chasing a butterfly across a meadow, cinematic",
    "resolution": "720p",
    "duration": 5,
}).json()

while task["status"] not in ("completed", "failed", "cancelled"):
    time.sleep(5)
    task = requests.get(task["status_url"], headers=HEADERS).json()

if task["status"] == "completed":
    url = task["data"][0]["url"]  # pre-signed, valid ~24 h - re-host promptly
    with open("out.mp4", "wb") as f:
        f.write(requests.get(url).content)
else:
    print(task["error"])  # provider code + message, passed through verbatim

Ejemplo - Node (fetch)

import fs from "node:fs";

const BASE = "https://synthorai.io/v1";
const HEADERS = { Authorization: `Bearer ${process.env.SYNTHORAI_API_KEY}` };

let task = await (await fetch(`${BASE}/videos`, {
  method: "POST",
  headers: { ...HEADERS, "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "seedance-1-5-pro-251215",
    prompt: "A corgi puppy chasing a butterfly across a meadow, cinematic",
    resolution: "720p",
    duration: 5,
  }),
})).json();

while (!["completed", "failed", "cancelled"].includes(task.status)) {
  await new Promise((r) => setTimeout(r, 5000));
  task = await (await fetch(task.status_url, { headers: HEADERS })).json();
}

if (task.status === "completed") {
  const url = task.data[0].url; // pre-signed, valid ~24 h — re-host promptly
  fs.writeFileSync("out.mp4", Buffer.from(await (await fetch(url)).arrayBuffer()));
} else {
  console.error(task.error); // provider code + message, passed through verbatim
}

Idempotencia

Pasa una cabecera X-Idempotency-Key en la llamada de creación para que los reintentos sean seguros: una petición repetida con la misma clave devuelve 409 en lugar de crear (y facturar) una segunda tarea. La generación de vídeo es lenta y propensa a reintentos - esto evita cargos dobles.