# Wan 3.0 API: text-to-video e image-to-video en Python

> Llama a Wan 3.0 desde Python: el script del 31 de octubre de 2026 para text-to-video e image-to-video, sus parámetros, clips reales, errores y el precio de Alibaba.

- Canonical HTML: https://omniakey.com/es/blog/wan-3-0-api
- Markdown: https://omniakey.com/es/blog/wan-3-0-api.md
- Published: 2026-10-31 (updated 2026-10-31)
- Author: Kiki, COO at OmniaKey
- Language: es
- Category: API setup
- Reading time: 8 min
- All posts: https://omniakey.com/blog/llms.txt

---

[Wan 3.0](https://omniakey.com/es/wan3-0-video) funciona en Alibaba Cloud Model Studio como `wan3.0-video` y la versión más rápida `wan3.0-video-prime`. Todas las llamadas son asíncronas: creas una tarea, consultas el ID y descargas el MP4. Nuestro script de Python generó un clip de 5 segundos en 720P a partir de texto en 2 min 42 s y otro a partir de una foto en 3 min 20 s, los dos con sonido.

1. Pon la clave en `OMNIAKEY_API_KEY`.
2. Haz POST a `https://api.omniakey.com/v1/media/tasks` con el modelo, la operación, el prompt, los parámetros y un `Idempotency-Key` nuevo.
3. Consulta `GET /v1/media/tasks/{id}` hasta que el estado diga succeeded y descarga `assets[0].url` en ese momento.

## ¿Existe una API oficial de Wan 3.0 y qué modelo conviene usar?

Sí. Alibaba Cloud Model Studio es la API oficial, con `wan3.0-video` y `wan3.0-video-prime` (referencia actualizada el 15 de octubre de 2026). Su llamada de creación necesita la cabecera `X-DashScope-Async: enable`, y Alibaba indica DashScope SDK 2.0.1 o posterior para Python.

||Alibaba Model Studio|OmniaKey|
|-|-|-|
|Ambos IDs|Sí|Sí|
|Cabecera asíncrona|Sí|No|
|Enlace del vídeo|24 horas|Cerca de 1 hora, renovable|
|Facturación|Por segundo|Por segundo|
|Python|DashScope SDK|Biblioteca estándar|

Los dos IDs comparten una sola forma de cuerpo, y el modelo elige el modo según el medio que envíes. El script de abajo ejecuta `wan3.0-video` y la línea `MODEL` lo cambia. No ejecutamos [Wan 3.0 Prime](https://omniakey.com/es/wan3-0-video-prime), que la documentación de OmniaKey describe con las mismas capacidades en aproximadamente la mitad del tiempo (comprobado el 31 de octubre de 2026).

## ¿Qué necesitas antes de la primera llamada?

Tres cosas, y la primera es la clave.

1. Una clave de API de OmniaKey, exportada en tu shell:

   ```bash
   export OMNIAKEY_API_KEY="your-key"
   ```

2. Python 3. El script solo importa la biblioteca estándar, así que python3 lo ejecuta tal cual.

3. Para image to video, un primer fotograma: un JPEG de unos 1024 px de ancho, o una URL HTTPS pública. El script rechaza un archivo de más de 700,000 bytes, porque Base64 añade un tercio y el límite del cuerpo es 1 MiB (documentación, comprobada el 31 de octubre de 2026).

## ¿Qué parámetros importan?

Siete campos hacen casi todo el trabajo, y cada uno es un valor dentro de `parameters`.

|Parámetro|Qué hace|Por defecto|
|-|-|-|
|Duration|Duración del clip, segundos|5|
|Resolution|Nivel de tamaño|1080P|
|Ratio|Forma del fotograma|adaptive|
|Audio|Pista de sonido|on|
|Seed|Ayuda a repetir|-1|
|Prompt extend|Reescribe tu prompt|on|
|Watermark|Añade una marca|off|

El script fija duration, resolution y ratio. Pide 720P cuando el valor por defecto de Alibaba es 1080P, que a precios de lista cuesta el doble por segundo.

## ¿Cómo es el código de Python?

El script de abajo se ejecutó sin cambios el 31 de octubre de 2026: solo biblioteca estándar, los dos modos y una línea MODEL que cambiar.

```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 = "wan3.0-video"

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):  # 5-second polls, up to 15 minutes
        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"]  # signed link: short-lived, so download now
    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"):
    with open(image_path, "rb") as f:
        raw = f.read()
    if len(raw) > 700_000:  # base64 adds a third, and the whole body must stay under 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"},
    }
    return run_task(body, out_path)

if __name__ == "__main__":
    print("done", text_to_video(
        "A blacksmith hammers a glowing horseshoe on an anvil in a dark forge. Sparks fly at each "
        "strike and light his leather apron. The camera slowly pushes in. Sound of the hammer ringing "
        "on steel and the fire crackling. No dialogue, no music, no text.",
        "forge.mp4",
    ))
    print("done", image_to_video(
        "Image 1 is the first frame. The paper boat drifts slowly to the right across the puddle. "
        "Light rain makes small ripples and the cafe lights shimmer in the water. The camera stays "
        "low and still. Sound of light rain. No dialogue, no music, no text.",
        "boat.jpg",
        "boat-drifts.mp4",
    ))
```

Qué hace cada parte:

- `run_task` acuña un `Idempotency-Key` nuevo para cada trabajo. Reenviar la misma clave con el mismo cuerpo devuelve la tarea original y nunca cobra dos veces (documentación, comprobada el 31 de octubre de 2026).
- Consulta cada 5 segundos hasta 15 minutos y después lanza TimeoutError.
- Un timeout significa consultar el mismo ID más tarde; un reenvío acuña una clave nueva, crea un segundo trabajo y lo factura.
- Descarga la primera URL del recurso en el acto, porque el enlace firmado dura poco.
- `image_to_video` rechaza un fotograma de más de 700,000 bytes: Base64 añade un tercio y el límite del cuerpo es 1 MiB.
- La llamada de imagen fija el ratio en `adaptive`, así el clip sigue la forma de la foto.

Esto es lo que imprimió:

```text
task task_<id>
done task_<id>
task task_<id>
done task_<id>
```

## ¿Qué produjeron las dos llamadas?

Los dos archivos volvieron como MP4 de 5.04 segundos, 150 fotogramas a 30 fps, H.264 y una pista AAC estéreo a 44.1 kHz.

### Text to video: la fragua

![Cuatro fotogramas del clip de la fragua de Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-forge-grid.4c1b058b.1288.webp)

_Text to video, 5 s en 720P: fotogramas en 0.3, 2.2, 3.5 y 4.7 segundos._

El clip sigue el prompt: un herrero con camisa oscura y delantal de cuero golpea una herradura naranja incandescente, las chispas estallan a los 2.2 segundos y la cámara se acerca un poco. El fallo es una marca de taller con letras ilegibles en el yunque, aunque el prompt pedía que no hubiera texto. Del inicio al archivo pasaron 2 min 42 s; el MP4 es de 1280×720 y 6.6 MB.

### Image to video: el barco de papel

![La foto del primer fotograma y tres fotogramas del clip del barco de papel de Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-paper-boat-grid.e2ffd154.1288.webp)

_Image to video: la foto que enviamos (arriba a la izquierda) y el clip en 1.6, 3.5 y 4.7 segundos._

El primer fotograma era una foto que hicimos con Nano Banana 2.1, un barco de papel rojo sobre un charco de lluvia, reducida a un JPEG de 1024×571 y 158 KB y enviada en línea como data URL. El clip mantiene esa luz de atardecer y los adoquines mojados, mueve el barco de izquierda a derecha como se pidió, hace ondas a los 1.6 segundos y mantiene la cámara baja y quieta. Volvió en 1284×716 porque adaptive siguió la forma de la foto, en 3 min 20 s y 7.4 MB.

### ¿Está activado el sonido y funciona "no music"?

El sonido está activado por defecto. Gemini 3.8 Flash describió la pista de la fragua como un tintineo metálico, sin voz ni música, y la del barco de papel como una melodía de piano melancólica y tranquila, aunque ese prompt terminaba en "no music". La [guía de prompts](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide) de Alibaba (actualizada el 16 de octubre de 2026) recomienda escribir "No BGM" o "No background music", y nuestro prompt no usó ninguna de las dos.

Con `"audio": false` el archivo solo lleva pista de vídeo: nuestro trabajo de farol de 2 segundos en 480P no tenía pista de sonido, y Alibaba cobra lo mismo en ambos casos.

|Clip|Tiempo|Tamaño|Sonido|
|-|-|-|-|
|Forja (texto)|2 min 42 s|1280×720|Tintineo, sin música|
|Barco de papel (imagen)|3 min 20 s|1284×716|Piano pese a "no music"|
|Linterna, sin audio|4 min 36 s|854×480|Sin pista de sonido|

El tiempo en cola varía: el trabajo de 2 segundos sin audio tardó 4 min 36 s, más que cualquiera de los dos clips de 5 segundos en 720P. Para redactar prompts, la [guía de prompts de Wan 3.0](https://omniakey.com/es/blog/wan-3-0-prompt-guide) tiene la estructura y ejemplos.

## ¿Cómo obtienes el archivo de vídeo y cuánto duran los enlaces?

Consulta `GET /v1/media/tasks/{id}` hasta que el estado diga succeeded, failed o canceled; mientras el trabajo corre dice queued o processing. Una tarea terminada devuelve una URL de recurso firmada que dura cerca de una hora (documentación de OmniaKey, comprobada el 31 de octubre de 2026). Descárgala en el acto y consulta la tarea otra vez para obtener una URL nueva cuando la anterior caduque, porque el registro vive 24 horas.

El archivo es un MP4 con vídeo H.264 a 30 fps, y la URL de vídeo de Alibaba dura 24 horas. Cancelar un trabajo de Wan 3.0 no detiene el render, y un trabajo que termina bien después de una cancelación se factura igual, así que revisa duration y resolution antes de enviar.

## ¿Qué errores vas a encontrar?

La mayoría vuelve antes de que exista una tarea, y cada uno se arregla en la petición o en la clave.

- **400 `model_price_error`** — duration fuera del rango de 2 a 30 segundos. Nuestra prueba con `"duration": 1` falló en 0.9 s con "media duration must be between 2 and 30 seconds"; no se creó ninguna tarea y no se cobró nada.
- **400 `missing_idempotency_key`** — falta la cabecera Idempotency-Key. Añade una, de hasta 255 caracteres.
- **409 `idempotency_key_reused`** — misma clave, cuerpo distinto. Acuña una clave nueva para cada prompt.
- **403 `model_not_allowed`** — la clave no puede llamar a ese modelo. Revisa el valor de `model` y luego los ajustes de la clave.
- **403 con un mensaje de saldo o de límite de gasto** — saldo bajo o un tope por clave. Recarga o sube el tope.
- **404 `task_not_found`** — ID equivocado, o una tarea de más de 24 horas. Consulta el ID que devolvió la llamada de creación.
- **409 `task_state_conflict`** — el trabajo ya terminó, como cuando una cancelación llega después del éxito. Lee el estado primero.
- **429** — demasiadas peticiones. OmniaKey no publica límites de tasa fijos, así que retrocede con espera exponencial y jitter.
- **503 `no_available_channel`** — no hay canal para esa operación, como video to video. Usa text to video o image to video.
- **`TimeoutError`** — sigue corriendo después de 15 minutos. Consulta el mismo ID más tarde; un reenvío crea y factura un segundo trabajo.

## ¿Cuánto cuesta un clip de Wan 3.0?

Alibaba cobra por segundo de vídeo, y una petición fallida no se cobra (página de precios actualizada el 29 de octubre de 2026). La tabla tiene los precios de lista de Alibaba en Singapur por segundo, comprobados el 31 de octubre de 2026 en la [página de precios de Model Studio](https://www.alibabacloud.com/help/en/model-studio/model-pricing).

|Model|480P|720P|1080P|
|-|-|-|-|
|Wan 3.0|$0.05|$0.1|$0.2|
|Wan 3.0 Prime|$0.068|$0.14|$0.28|

Un clip de 5 segundos en 720P cuesta $0.50 en Wan 3.0 (5 × $0.1) y $0.70 en Prime (5 × $0.14). Los tres precios de Wan 3.0 llevan la marca "Limited-time 30% off", y la página no dice si las cifras la incluyen. Con sonido o sin él cuesta lo mismo.

La cuota gratuita es de 30 segundos de vídeo, entrada más salida, en `wan3.0-video` en Singapur; Prime no tiene ninguna. Alibaba lista tarifas en dólares más bajas en China (Pekín) para el modelo estándar: $0.041256, $0.082513 y $0.165025 por segundo en 480P, 720P y 1080P.

OmniaKey también cobra por segundo, con las tarifas actuales en las páginas de [Wan 3.0](https://omniakey.com/es/wan3-0-video) y [Wan 3.0 Prime](https://omniakey.com/es/wan3-0-video-prime).

## Preguntas frecuentes

### ¿Cuánto tarda una llamada?

Alibaba dice que un trabajo suele tardar de 1 a 5 minutos y recomienda consultar cada 15 segundos (referencia, comprobada el 31 de octubre de 2026). Nuestros tres trabajos tardaron 2 min 42 s, 3 min 20 s y 4 min 36 s.

### ¿Cómo desactivo el sonido?

Pon `"audio": false` dentro de `parameters` y el MP4 llega solo con pista de vídeo, como pasó con el trabajo del farol. El precio no cambia.

### ¿Uso wan3.0-video o wan3.0-video-prime?

Elige `wan3.0-video` por la tarifa de lista más baja de Alibaba y su cuota gratuita de 30 segundos en Singapur, y Prime cuando el tiempo importe más. OmniaKey describe Prime como las mismas capacidades en aproximadamente la mitad del tiempo.

### ¿Cuánto dura el enlace del vídeo?

Cerca de una hora en OmniaKey, y consultar la tarea otra vez devuelve un enlace nuevo mientras el registro dura 24 horas. La URL de vídeo de Alibaba dura 24 horas.

## Fuentes consultadas

- [Referencia de la API de generación de vídeo de Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-api-reference), comprobada el 31 de octubre de 2026
- [Guía de generación de vídeo de Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-guide), comprobada el 31 de octubre de 2026
- [Guía de prompts para la generación de vídeo de Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide), comprobada el 31 de octubre de 2026
- [Precios de los modelos de Alibaba Cloud Model Studio](https://www.alibabacloud.com/help/en/model-studio/model-pricing), comprobada el 31 de octubre de 2026
- [Documentación de la API de vídeo de OmniaKey](https://docs.omniakey.com/en/media/video), comprobada el 31 de octubre de 2026
- [Descripción general de la API de medios de OmniaKey](https://docs.omniakey.com/en/media/overview), comprobada el 31 de octubre de 2026
- [Códigos de error de la API de OmniaKey](https://docs.omniakey.com/en/api/errors), comprobada el 31 de octubre de 2026
