# Wan 3.0 API: come creare video da testo e da immagine in Python

> Chiamare Wan 3.0 da Python: lo script che abbiamo eseguito il 31 ottobre 2026 per testo e immagine in video, i parametri, clip reali, errori e il prezzo di Alibaba.

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

---

[Wan 3.0](https://omniakey.com/it/wan3-0-video) gira su Alibaba Cloud Model Studio come `wan3.0-video` e come `wan3.0-video-prime`, più veloce. Ogni chiamata è asincrona: crei un task, interroghi l'ID, scarichi l'MP4. Il nostro script Python ha prodotto una clip 720P di 5 secondi da un testo in 2 min 42 s e una da una foto ferma in 3 min 20 s, entrambe con l'audio.

1. Metti la chiave in `OMNIAKEY_API_KEY`.
2. Fai una POST a `https://api.omniakey.com/v1/media/tasks` con modello, operazione, prompt, parametri e una nuova `Idempotency-Key`.
3. Interroga `GET /v1/media/tasks/{id}` finché lo stato non è succeeded, poi scarica subito `assets[0].url`.

## Esiste un'API ufficiale di Wan 3.0, e quale modello uso?

Sì. L'API ufficiale è Alibaba Cloud Model Studio, con `wan3.0-video` e `wan3.0-video-prime` (riferimento aggiornato il 15 ottobre 2026). La chiamata di creazione richiede l'header `X-DashScope-Async: enable`, e la via Python di Alibaba è DashScope SDK 2.0.1 o successivo.

||Alibaba Model Studio|OmniaKey|
|-|-|-|
|I due ID modello|Sì|Sì|
|Header async|Serve|Non serve|
|Link al video|24 ore|Circa 1 ora, rinnovabile|
|Addebito|Al secondo|Al secondo|
|Python|DashScope SDK|Libreria standard|

I due ID accettano lo stesso body, e il modello sceglie la modalità dal media che invii. Lo script sotto esegue `wan3.0-video`, e la riga `MODEL` lo cambia. Non abbiamo eseguito [Wan 3.0 Prime](https://omniakey.com/it/wan3-0-video-prime), che la documentazione di OmniaKey descrive con le stesse capacità e tempi circa dimezzati (verificato il 31 ottobre 2026).

## Cosa serve prima della prima chiamata?

Tre cose, e la prima è la chiave:

1. Una chiave API OmniaKey, esportata nella shell:

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

2. Python 3. Lo script importa solo la libreria standard, quindi python3 lo esegue così com'è.

3. Per image to video serve un primo fotogramma: un JPEG largo circa 1024 px, oppure un URL HTTPS pubblico. Lo script rifiuta un file oltre 700.000 byte, perché Base64 aggiunge un terzo e il limite del body è 1 MiB (documentazione, verificata il 31 ottobre 2026).

## Quali parametri contano?

Sette campi fanno quasi tutto il lavoro, e ognuno è un valore dentro `parameters`.

|Parametro|A cosa serve|Default|
|-|-|-|
|Durata|Lunghezza della clip, secondi|5|
|Risoluzione|Fascia di dimensione dell'immagine|1080P|
|Proporzioni|Forma del fotogramma|adaptive|
|Audio|Traccia sonora|attivo|
|Seed|Indizio di ripetibilità|-1|
|Prompt extend|Riscrive il tuo prompt|attivo|
|Watermark|Aggiunge un segno nell'angolo|spento|

Lo script imposta durata, risoluzione e proporzioni. Chiede 720P mentre il default di Alibaba è 1080P, che ai prezzi di listino costa il doppio al secondo.

## Come è fatto il codice Python?

Lo script sotto ha girato senza modifiche il 31 ottobre 2026: solo libreria standard, due modalità, una riga MODEL da cambiare.

```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",
    ))
```

Cosa fa ogni parte:

- `run_task` genera una nuova `Idempotency-Key` per ogni job. Rimandare la stessa chiave con lo stesso body restituisce il task originale e non addebita due volte (documentazione, verificata il 31 ottobre 2026).
- Interroga ogni 5 secondi per un massimo di 15 minuti, poi solleva TimeoutError.
- Un timeout significa interrogare di nuovo lo stesso ID più tardi; un nuovo invio genera una chiave nuova, crea un secondo job e lo fattura.
- Scarica subito il primo URL dell'asset, perché il link firmato dura poco.
- `image_to_video` rifiuta un fotogramma oltre 700.000 byte: Base64 aggiunge un terzo e il limite del body è 1 MiB.
- La chiamata con immagine imposta le proporzioni su `adaptive`, così la clip segue la forma della foto ferma.

Cosa stampa:

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

## Cosa hanno prodotto le due chiamate?

Entrambi i file sono tornati come MP4 da 5.04 secondi, 150 fotogrammi a 30 fps, H.264, con traccia stereo AAC a 44.1 kHz.

### Testo in video: la forgia

![Quattro fotogrammi dalla clip della forgia di Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-forge-grid.4c1b058b.1288.webp)

_Testo in video, 5 s a 720P: fotogrammi a 0.3, 2.2, 3.5 e 4.7 secondi._

La clip segue il prompt: un fabbro in camicia scura e grembiule di cuoio martella un ferro di cavallo arancione incandescente, a 2.2 secondi partono le scintille e la camera si avvicina un po'. Il difetto è un marchio del fabbro con lettere illeggibili sull'incudine, anche se il prompt chiedeva nessun testo. Dall'avvio al file sono passati 2 min 42 s; l'MP4 è 1280×720 a 6.6 MB.

### Immagine in video: la barca di carta

![La foto ferma del primo fotogramma e tre fotogrammi dalla clip della barca di carta di Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-paper-boat-grid.e2ffd154.1288.webp)

_Immagine in video: la foto ferma che abbiamo inviato (in alto a sinistra), poi la clip a 1.6, 3.5 e 4.7 secondi._

Il primo fotogramma era una foto ferma fatta con Nano Banana 2.1, una barca di carta rossa su una pozzanghera, ridimensionata a un JPEG 1024×571 da 158 KB e inviata inline come data URL. La clip mantiene quella luce di crepuscolo e i sampietrini bagnati, sposta la barca da sinistra a destra come richiesto, crea increspature a 1.6 secondi e tiene la camera bassa e ferma. È tornata 1284×716 perché adaptive ha seguito la forma della foto, in 3 min 20 s a 7.4 MB.

### L'audio è attivo, e "no music" funziona?

L'audio è attivo per default. Gemini 3.8 Flash ha descritto la traccia della forgia come tintinnio metallico senza parlato e senza musica, e quella della barca di carta come una melodia di pianoforte malinconica e calma, anche se quel prompt finiva con "no music". La [guida ai prompt](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide) di Alibaba (aggiornata il 16 ottobre 2026) consiglia di scrivere "No BGM" o "No background music", e il nostro prompt non usava nessuno dei due.

Con `"audio": false` il file porta solo la traccia video: il nostro job della lanterna, 2 secondi a 480P, non aveva traccia audio, e Alibaba fattura lo stesso in entrambi i casi.

|Clip|Tempo|Dimensione|Audio|
|-|-|-|-|
|Forgia (testo)|2 min 42 s|1280×720|Tintinnio, niente musica|
|Barca di carta (immagine)|3 min 20 s|1284×716|Pianoforte nonostante "no music"|
|Lanterna, audio off|4 min 36 s|854×480|Nessuna traccia audio|

Il tempo in coda varia: il job da 2 secondi con audio off ha impiegato 4 min 36 s, più di entrambe le clip 720P da 5 secondi. Per come scrivere il prompt, la [guida ai prompt di Wan 3.0](https://omniakey.com/it/blog/wan-3-0-prompt-guide) ha la struttura e prompt di esempio.

## Come si scarica il file video, e quanto durano i link?

Interroga `GET /v1/media/tasks/{id}` finché lo stato non è succeeded, failed o canceled; mentre il job gira lo stato è queued o processing. Un task finito restituisce un URL firmato dell'asset che dura circa un'ora (documentazione OmniaKey, verificata il 31 ottobre 2026). Scaricalo subito, poi interroga di nuovo il task per un URL fresco quando il vecchio scade, perché il record vive 24 ore.

L'MP4 ha video H.264 a 30 fps, e l'URL video di Alibaba dura 24 ore. Annullare un job Wan 3.0 non ferma il render, e un job che riesce dopo l'annullamento viene fatturato lo stesso, quindi controlla durata e risoluzione prima di inviare.

## Quali errori incontrerai?

La maggior parte arriva prima che esista un task, e ognuno ha una correzione nella richiesta o nella chiave.

- **400 `model_price_error`** — durata fuori dai 2-30 secondi. Il nostro test con `"duration": 1` è fallito in 0.9 s con "media duration must be between 2 and 30 seconds"; nessun task creato e niente fatturato.
- **400 `missing_idempotency_key`** — manca l'header Idempotency-Key. Aggiungine uno, fino a 255 caratteri.
- **409 `idempotency_key_reused`** — stessa chiave, body diverso. Genera una chiave nuova per ogni prompt.
- **403 `model_not_allowed`** — la chiave non può chiamare quel modello. Controlla il valore `model`, poi le impostazioni della chiave.
- **403 con un messaggio su saldo o limite di spesa** — saldo basso o limite per chiave. Ricarica o alza il limite.
- **404 `task_not_found`** — ID sbagliato, o task più vecchio di 24 ore. Interroga l'ID restituito dalla chiamata di creazione.
- **409 `task_state_conflict`** — il job è già finito, per esempio un annullamento arrivato dopo il successo. Leggi prima lo stato.
- **429** — troppe richieste. OmniaKey non pubblica limiti di frequenza fissi, quindi fai backoff con attesa esponenziale e jitter.
- **503 `no_available_channel`** — nessun canale per quell'operazione, come video to video. Usa text to video o image to video.
- **`TimeoutError`** — ancora in esecuzione dopo 15 minuti. Interroga lo stesso ID più tardi; un nuovo invio crea e fattura un secondo job.

## Quanto costa una clip di Wan 3.0?

Alibaba fattura al secondo di video, e una richiesta fallita non viene fatturata (pagina dei prezzi aggiornata il 29 ottobre 2026). La tabella riporta i prezzi di listino di Alibaba a Singapore al secondo, verificati il 31 ottobre 2026, dalla [pagina dei prezzi di Model Studio](https://www.alibabacloud.com/help/en/model-studio/model-pricing) di Alibaba.

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

Secondo Alibaba una clip 720P da 5 secondi costa $0.50 su Wan 3.0 (5 × $0.1) e $0.70 su Prime (5 × $0.14). I tre prezzi di Wan 3.0 hanno la scritta "Limited-time 30% off", e la pagina non dice se le cifre la includono. Con audio on o off il prezzo è lo stesso.

La quota gratuita di Alibaba è 30 secondi di video, input più output, su `wan3.0-video` a Singapore; Prime non ne ha. La regione Cina (Pechino) di Alibaba elenca tariffe in dollari più basse per il modello standard: $0.041256, $0.082513 e $0.165025 al secondo a 480P, 720P e 1080P.

Anche OmniaKey fattura al secondo, con le tariffe attuali nelle pagine dei modelli [Wan 3.0](https://omniakey.com/it/wan3-0-video) e [Wan 3.0 Prime](https://omniakey.com/it/wan3-0-video-prime).

## Domande frequenti

### Quanto dura una chiamata?

Alibaba dice che un job richiede di solito da 1 a 5 minuti e consiglia di interrogare ogni 15 secondi (riferimento, verificato il 31 ottobre 2026). I nostri tre job hanno impiegato 2 min 42 s, 3 min 20 s e 4 min 36 s.

### Come disattivo l'audio?

`"audio": false` dentro `parameters` fa arrivare l'MP4 con la sola traccia video, come nel nostro job della lanterna. Il prezzo resta uguale.

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

Scegli `wan3.0-video` per la tariffa di listino più bassa di Alibaba e per la quota gratuita di 30 secondi a Singapore, e Prime quando conta di più il tempo di elaborazione. OmniaKey descrive Prime con le stesse capacità e circa metà del tempo.

### Quanto dura il link del video?

Circa un'ora su OmniaKey, e interrogare di nuovo il task restituisce un link fresco finché il record dura 24 ore. L'URL video di Alibaba dura 24 ore.

## Fonti verificate

- [Riferimento API per la generazione video di Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-api-reference), verificato il 31 ottobre 2026
- [Guida alla generazione video di Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-guide), verificato il 31 ottobre 2026
- [Guida ai prompt per la generazione video di Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide), verificato il 31 ottobre 2026
- [Prezzi dei modelli di Alibaba Cloud Model Studio](https://www.alibabacloud.com/help/en/model-studio/model-pricing), verificato il 31 ottobre 2026
- [Documentazione video API di OmniaKey](https://docs.omniakey.com/en/media/video), verificato il 31 ottobre 2026
- [Panoramica delle media API di OmniaKey](https://docs.omniakey.com/en/media/overview), verificato il 31 ottobre 2026
- [Codici di errore API di OmniaKey](https://docs.omniakey.com/en/api/errors), verificato il 31 ottobre 2026
