GPT-6 Sol y Claude Opus 5.5 ya disponiblesGPT-6 Sol por la mitad del precio de 5.6 Sol

API de Seedance 2.0: de texto a video y de imagen a video con Python

Un script crea la tarea, consulta su estado y guarda el MP4. Aquí están los campos, los límites y dos clips de 5 segundos que hicimos el 30 de octubre de 2026.

Kiki, OmniaKey COO11 min de lectura
En esta página

Seedance 2.0 corre en la API de medios de OmniaKey con el id de modelo dreamina-seedance-2-0-260128. Envías una tarea con POST a https://api.omniakey.com/v1/media/tasks, consultas el id de la tarea y descargas el MP4. Nuestros dos clips de 5 segundos en 720p, uno desde texto y otro desde una imagen fija, tardaron 159 y 139 segundos el 30 de octubre de 2026.

Respuesta corta

  • Id de modelo dreamina-seedance-2-0-260128, con tres operaciones: text_to_video, image_to_video y reference_to_video (documentación de la API de video de OmniaKey, consultada el 30 de octubre de 2026).
  • Crear, consultar, descargar: la llamada de creación responde 202 con un id y después haces GET a /v1/media/tasks/{id} cada pocos segundos hasta que el estado sea succeeded (documentación de la API de medios de OmniaKey, consultada el 30 de octubre de 2026).
  • La duración va de 4 a 15 segundos enteros y el id completo de 2.0 genera 480P, 720P y 1080P.
  • Todo el cuerpo de la petición queda por debajo de 1 MiB, incluido el base64 en línea.
  • Nuestros dos videos de 5 segundos en 720p terminaron en 159 segundos (texto a video) y 139 segundos (primer fotograma).

¿Qué necesitas antes de la primera llamada?

Una clave de API de OmniaKey, Python 3 y el id de modelo exacto. El script importa solo la biblioteca estándar, así que corre sin entorno virtual y sin instalar paquetes.

Exporta la clave como OMNIAKEY_API_KEY antes de la primera llamada. El script la lee una vez y la envía como token Bearer en cada petición, así que la clave no queda en el archivo ni en tu historial de git.

Crea con POST https://api.omniakey.com/v1/media/tasks y consulta con GET https://api.omniakey.com/v1/media/tasks/{id}. Esas dos más POST /v1/media/tasks/{id}/cancel son toda la API de medios (API de medios, consultada el 30 de octubre de 2026).

Escribe los id de modelo completos. OmniaKey no sirve los alias cortos seedance-2 y seedance-2-5, y responden 503 no_available_channel (API de video, consultada el 30 de octubre de 2026).

Los trabajos de video se cobran por adelantado por segundo de resultado, y el cargo vuelve solo cuando un trabajo termina en failed o canceled (API de medios, consultada el 30 de octubre de 2026). Para saber cuánto cuesta cada segundo ahora, mira las tarifas actuales en la página del modelo Seedance 2.0.

¿Qué campos lleva una petición de Seedance 2.0?

Cuatro campos de primer nivel llevan el trabajo y un objeto parameters lleva los ajustes de salida. Solo duration no tiene un valor por defecto razonable, así que mándalo siempre.

  • model: el id completo (los alias cortos fallan)
  • type: video (el tipo de medio)
  • operation: text_to_video, image_to_video, reference_to_video (nombre simple, sin prefijo)
  • input.prompt: una cadena (escena, acción y cámara, hasta 12.000 caracteres)
  • input.media[]: {"type": "first_frame", "url": …} (un primer fotograma o reference_image)

Dentro de parameters:

  • duration: 4 a 15, segundos enteros (decide el precio)
  • resolution: 480P, 720P, 1080P (Fast y Mini se quedan en 720P)
  • ratio: 16:9, 9:16, 1:1, 4:3, 3:4, 21:9, adaptive (adaptive sigue al fotograma)
  • generate_audio: true por defecto, o false (false da un MP4 sin sonido)
  • n: 1 (debe ser 1)

Las dos listas siguen la documentación de la API de video y la API de medios de OmniaKey (consultadas el 30 de octubre de 2026), y el límite del prompt viene de la página del modelo.

Manda el nombre de la operación sin prefijo; OmniaKey añade el prefijo del tipo de medio (API de video, consultada el 30 de octubre de 2026). Los parámetros que no reconoce pasan al proveedor tal cual (API de medios, consultada el 30 de octubre de 2026).

Una trampa pilla a quien empieza por la documentación del proveedor: la API de creación de tareas de BytePlus pone los campos dentro de content[] y en el primer nivel, así que el código de un tutorial de BytePlus no corre igual contra /v1/media/tasks (API de creación de tareas de BytePlus, consultada el 30 de octubre de 2026).

El script de Python

Un archivo ejecuta las dos operaciones y la única diferencia es el cuerpo que arma. Guárdalo como seedance_video.py y ejecuta python3 seedance_video.py.

python
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid

API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "dreamina-seedance-2-0-260128"

def request(method, url, body=None, extra_headers=None):
    headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
    data = None
    if body is not None:
        headers["Content-Type"] = "application/json"
        data = json.dumps(body).encode()
    headers.update(extra_headers or {})
    req = urllib.request.Request(url, data=data, headers=headers, method=method)
    with urllib.request.urlopen(req, timeout=120) as resp:
        return json.load(resp)

def poll(url, attempts=5):
    for attempt in range(attempts):
        try:
            return request("GET", url)
        except urllib.error.HTTPError as err:
            if err.code < 500 or attempt == attempts - 1:
                raise
        except urllib.error.URLError:
            if attempt == attempts - 1:
                raise
        time.sleep(5 * (attempt + 1))

def run_task(body, out_path):
    task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
    print("task", task, flush=True)
    for _ in range(180):  # consultas cada 5 segundos, hasta 15 minutos
        time.sleep(5)
        state = poll(f"{API}/{task}")
        if state["status"] not in ("queued", "processing"):
            break
    else:
        raise TimeoutError(f"{task} is still {state['status']}: poll it again later, do not resubmit")
    if state["status"] != "succeeded":
        raise RuntimeError(state.get("error") or state["status"])
    asset_url = state["assets"][0]["url"]  # enlace firmado: dura poco, descarga ahora
    req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
    with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
        f.write(resp.read())
    return task

def text_to_video(prompt, out_path, duration=5, resolution="720P", ratio="16:9"):
    body = {
        "model": MODEL,
        "type": "video",
        "operation": "text_to_video",
        "input": {"prompt": prompt},
        "parameters": {"duration": duration, "resolution": resolution, "ratio": ratio},
    }
    return run_task(body, out_path)

def image_to_video(prompt, image_path, out_path, duration=5, resolution="720P", audio=False):
    with open(image_path, "rb") as f:
        raw = f.read()
    if len(raw) > 700_000:  # base64 añade un tercio y el cuerpo debe quedar bajo 1 MiB
        raise ValueError("first frame too large: save it as a JPEG about 1024 px wide")
    frame = "data:image/jpeg;base64," + base64.b64encode(raw).decode()
    body = {
        "model": MODEL,
        "type": "video",
        "operation": "image_to_video",
        "input": {"prompt": prompt, "media": [{"type": "first_frame", "url": frame}]},
        "parameters": {"duration": duration, "resolution": resolution, "ratio": "adaptive",
                       "generate_audio": audio},
    }
    return run_task(body, out_path)

if __name__ == "__main__":
    print("done", text_to_video(
        "Close-up of a tall glass on a wooden bar counter. Sparkling water is poured over ice; bubbles "
        "rise and the ice cubes clink and shift. Warm evening light from the left. The camera slowly "
        "pushes in. Sound of pouring, fizzing and clinking ice. No people, no text.",
        "sparkling-glass.mp4",
    ))
    print("done", image_to_video(
        "The cat slowly wakes, stretches its front paws and yawns, then looks toward the window. "
        "Raindrops keep running down the glass. The camera stays still.",
        "cat.jpg",
        "cat-wakes.mp4",
    ))

Seis partes de este archivo importan antes de cambiar nada.

  • Cada petición de creación lleva una Idempotency-Key aleatoria; repetir esa clave con el mismo cuerpo devuelve la tarea original con HTTP 200 y nunca cobra dos veces (API de medios, consultada el 30 de octubre de 2026).
  • El bucle duerme 5 segundos entre consultas y para tras 180 intentos, que son 15 minutos.
  • Un tiempo de espera agotado significa que el trabajo sigue renderizando. Consulta el mismo id de tarea más tarde y nunca lo reenvíes, o pagas un segundo clip.
  • assets[0].url es un enlace firmado que dura cerca de una hora, así que el script descarga en cuanto la tarea termina bien (API de medios, consultada el 30 de octubre de 2026).
  • progress.percent puede quedarse en 0 mientras el trabajo corre, así que el bucle sigue status y nada más (API de video, consultada el 30 de octubre de 2026).
  • La función de imagen rechaza un archivo de más de 700.000 bytes, porque base64 añade un tercio y el cuerpo tiene que quedar por debajo de 1 MiB.

La forma de la petición coincide con Kling 3.0 en la misma API, así que cambiar de modelo cambia el id y los parámetros, no el código de alrededor.

¿Cómo se envía el primer fotograma para imagen a video?

Pon la imagen en input.media[] con "type": "first_frame", en línea como URI data:image/jpeg;base64,..., la forma que usó nuestro clip del gato.

input.media[] acepta una URL HTTPS pública o un URI de datos en línea, y todo el cuerpo está limitado a 1 MiB (API de video, consultada el 30 de octubre de 2026). En la propia prueba de OmniaKey un enlace HTTPS normal de fotograma fue rechazado con provider_submit_rejected, por eso el ejemplo manda un URI de datos (API de video, consultada el 30 de octubre de 2026).

Base64 añade un tercio, así que empieza por un JPEG de unos 1024 píxeles de ancho: nuestro primer fotograma pesaba 134.356 bytes y un PNG de 4 MB sería rechazado.

Mantén parameters.ratio en adaptive aquí: sigue la forma de la imagen que enviaste, y así una foto de 1024×571 se convirtió en un clip de 1280×720. Para reference_to_video, el mismo arreglo acepta "type": "reference_image" (API de video, consultada el 30 de octubre de 2026).

Dos clips que hicimos

Las dos tareas salieron el 30 de octubre de 2026 con el archivo de arriba, sin cambios. La primera es texto a video, tarea task_uF2QUtbeAAUW11lXEaLxNw1ZnBUoqvNk, creada a las 01:39:43 UTC y terminada con éxito a las 01:42:22 UTC. El prompt pedía el sonido del vertido, así que el audio quedó activado.

prompt
Close-up of a tall glass on a wooden bar counter. Sparkling water is poured over ice; bubbles rise and the ice cubes clink and shift. Warm evening light from the left. The camera slowly pushes in. Sound of pouring, fizzing and clinking ice. No people, no text.
Ocho fotogramas de un vaso alto de agua con gas sobre una barra de madera, desde el vertido en vacío hasta un vaso lleno con burbujas cerca del fondo.
Ocho fotogramas del clip del vaso en orden temporal, de 0,0 a 5,0 segundos. Seedance 2.0 vía la API de OmniaKey, texto a video, 5 segundos, 720P, hecho el 30 de octubre de 2026.

Los fotogramas muestran un vaso con hielo sobre una barra de madera, con botellas y luces cálidas desenfocadas detrás. El vaso crece del primer fotograma al último, que es el acercamiento que pedía el prompt, y termina lleno con burbujas cerca del fondo.

El segundo es imagen a video, tarea task_u85W0jn1sQLkrszJlxqXF1hxJYhsndxK, creada a las 01:42:33 UTC y terminada con éxito a las 01:44:52 UTC. El primer fotograma es una foto de un gato atigrado naranja dormido sobre una pila de libros viejos junto a una ventana con lluvia (1024×571 píxeles), enviada como URI de datos con "type": "first_frame".

prompt
The cat slowly wakes, stretches its front paws and yawns, then looks toward the window. Raindrops keep running down the glass. The camera stays still.
Ocho fotogramas de un gato atigrado naranja dormido sobre una pila de libros junto a una ventana con lluvia, despertando, estirando las patas y bostezando.
Ocho fotogramas del clip del gato en orden temporal, de 0,0 a 5,0 segundos. Seedance 2.0 vía la API de OmniaKey, imagen a video, 5 segundos, 720P, hecho el 30 de octubre de 2026.

El gato levanta la cabeza, abre los ojos, estira las dos patas delanteras por el borde de los libros, bosteza amplio y gira la cabeza hacia la ventana, en el orden que dio el prompt. La lluvia sigue corriendo por el cristal y el encuadre se queda quieto, como se pidió.

A la izquierda, la foto del gato atigrado enviada como primer fotograma; a la derecha, el último fotograma del clip, con las patas estiradas sobre los libros y la cabeza girada hacia la ventana.
Izquierda: la foto enviada como primer fotograma. Derecha: el último fotograma del clip del gato. Seedance 2.0 vía la API de OmniaKey, imagen a video, 5 segundos, 720P, hecho el 30 de octubre de 2026.

Estas dos ejecuciones cubren texto a video y un primer fotograma en 720P durante 5 segundos. No probamos 1080P, Fast, Mini, 2.5, reference_to_video, un enlace HTTPS de fotograma ni ninguna otra duración.

Lo que midieron los archivos

Las dos descargas son MP4 H.264 de 1280×720 y 24 fps: 121 fotogramas, 5,04 segundos.

ClipVasoGato
Operacióntexto a videoimagen a video
Tiempo hasta terminar159 s139 s
Tamaño2.070.248 bytes1.352.027 bytes
Video1280×720, 24 fps, 121 fotogramas1280×720, 24 fps, 121 fotogramas
Audiopista AACninguna

El clip del vaso lleva vertido, burbujas y hielo chocando, sin voces ni música. El del gato no tiene pista de audio, porque la petición mandó generate_audio: false.

Los dos registros de tarea informaron usage.completion_tokens: 108900, que es 121 × 1280 × 720 ÷ 1024, la fórmula de tokens que BytePlus usa para estimar el cobro del video (página de precios de BytePlus, consultada el 30 de octubre de 2026).

La documentación de OmniaKey dice que un clip de 6 segundos en 720p suele terminar en alrededor de un minuto (API de video, consultada el 30 de octubre de 2026). Los nuestros tardaron 159 y 139 segundos, y tres clips de 5 segundos en 720p de nuestra comparación del 26 de octubre tardaron 144,8, 319,0 y 184,7 segundos. Calcula de 2 a 5 minutos y consulta en vez de dejar una petición abierta.

¿Qué errores y límites vas a encontrar?

Revisa tres ajustes primero: el id de modelo, una duración de 4 a 15 y el audio, que el filtro del proveedor puede rechazar.

Estado / CódigoQué cambiar
400 invalid_requestel cuerpo o input.prompt
400 model_price_errorduración de 4 a 15 s
403 model_not_allowedacceso a modelos de la clave
409 idempotency_key_reuseduna clave nueva por cuerpo
503 no_available_channelid completo, operación sin prefijo
tarea fallida, error del proveedorlee error y reintenta

Esos códigos vienen de la API de medios y de la API de video (consultadas el 30 de octubre de 2026). Una tarea que termina en failed devuelve el cargo por adelantado, así que un render rechazado solo te cuesta tiempo.

Vigila el ajuste de audio. Seedance genera una pista por defecto, y dejarlo activado hizo que el proveedor rechazara una petición de 4 segundos en 480P con OutputAudioSensitiveContentDetected.PolicyViolation, así que manda parameters.generate_audio: false salvo que la escena necesite sonido (API de video, consultada el 30 de octubre de 2026).

BytePlus dice que la serie 2.0 no acepta imágenes ni videos de referencia que contengan caras humanas reales (página de Seedance 2.0 de BytePlus, consultada el 30 de octubre de 2026). Seedance 2.0 tampoco tiene seed ni camera_fixed, aunque ambos son campos de la API de creación de tareas del proveedor (API de creación de tareas de BytePlus, consultada el 30 de octubre de 2026).

Quince segundos es el techo de esta familia, y duration: -1 no compra más; una toma de 20 o 30 segundos va en Seedance 2.5 (página del modelo Seedance 2.0, consultada el 30 de octubre de 2026).

OmniaKey no publica límites de frecuencia fijos; trata un HTTP 429 como reintentable con espera creciente (página de errores de la API de OmniaKey, consultada el 30 de octubre de 2026).

¿Seedance 2.0, Fast, Mini o 2.5?

Cuatro niveles aceptan el mismo cuerpo de petición, así que cambiar cuesta un id de modelo y, en Fast y Mini, un techo de resolución más bajo.

  • Seedance 2.0, dreamina-seedance-2-0-260128: 480P, 720P y 1080P, de 4 a 15 segundos. El precio de lista de BytePlus para un clip de 5 segundos es $0.76 en 720p y $0.35 en 480p (página de precios de BytePlus, consultada el 30 de octubre de 2026).
  • Seedance 2.0 Fast, dreamina-seedance-2-0-fast-260128: 480P y 720P, de 4 a 15 segundos. El precio de lista de BytePlus para un clip de 5 segundos es $0.60 en 720p y $0.28 en 480p.
  • Seedance 2.0 Mini, dreamina-seedance-2-0-mini-260615: 480P y 720P, de 4 a 15 segundos. El precio de lista de BytePlus para un clip de 5 segundos es $0.38 en 720p y $0.18 en 480p.
  • Seedance 2.5, dreamina-seedance-2-5-260628: el único id de la familia que acepta una toma de 20 o 30 segundos, y el más lento: unos cuatro minutos para un clip de 4 segundos en 480P (API de video, consultada el 30 de octubre de 2026). Nuestra reseña de Seedance 2.5 cubre el lado de la imagen.

Las páginas de modelo de OmniaKey indican que un clip de 4 segundos en 480P tarda alrededor de un minuto en 2.0, dos minutos en Fast y 100 segundos en Mini (consultadas el 30 de octubre de 2026).

Toma el id completo de 2.0 cuando necesites un máster en 1080P, porque Fast y Mini se quedan en 720P (API de video, consultada el 30 de octubre de 2026). OmniaKey fija sus propias tarifas para estos id, así que mira las actuales en la página del modelo Seedance 2.0.

Preguntas frecuentes

¿Existe una API oficial de Seedance 2.0?

Sí. BytePlus ModelArk la vende, y activarla allí requiere un saldo de cuenta superior a USD 30, un Savings Plan o un paquete de recursos de Seedance (página de Seedance 2.0 de BytePlus, consultada el 30 de octubre de 2026). El script de arriba llama al mismo id de modelo a través de la API de medios de OmniaKey.

¿Puedo mandar una URL de imagen en vez de base64?

La documentación de OmniaKey lista una URL HTTPS pública junto al URI de datos en línea (API de video, consultada el 30 de octubre de 2026). Nuestras ejecuciones fueron en línea porque un enlace HTTPS de fotograma volvió como provider_submit_rejected en la propia prueba de OmniaKey, así que prueba una URL con un clip de test primero.

¿Cómo apago el sonido?

Manda parameters.generate_audio: false y el MP4 llega sin pista de audio, como el clip del gato. El audio viene activado por defecto en este modelo.

¿Por qué se agotó el tiempo de mi petición?

El clip suele seguir renderizando, porque los trabajos de 5 segundos en 720p tardaron entre 139 y 319 segundos en nuestras ejecuciones. Consulta el mismo id de tarea otra vez, no reenvíes, y sube el límite de 15 minutos del bucle para clips de 15 segundos.

¿Cuánto duran los enlaces del video?

El enlace firmado de assets[0].url dura cerca de una hora, y el registro de la tarea se guarda 24 horas desde su creación (API de medios, consultada el 30 de octubre de 2026). Descarga en el primer éxito o consulta la tarea otra vez para un enlace nuevo.

Fuentes consultadas

Documentación de OmniaKey, consultada el 30 de octubre de 2026: API de video, API de medios y errores de la API.

Modelos de este artículo

Seedance 2.0video con IAAPI de videoimagen a videoPython

Artículos relacionados

Artículos recientes