# Wan 3.0 API: text-to-video dan image-to-video lewat Python

> Panggil Wan 3.0 dari Python: skrip yang kami jalankan pada 31 Oktober 2026 untuk text-to-video dan image-to-video, parameternya, klip asli, error, dan harga Alibaba.

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

---

[Wan 3.0](https://omniakey.com/id/wan3-0-video) berjalan di Alibaba Cloud Model Studio sebagai `wan3.0-video` dan versi lebih cepat `wan3.0-video-prime`. Setiap panggilan asinkron: buat tugas, polling ID, unduh MP4. Skrip Python kami membuat klip 720P 5 detik dari teks dalam 2 min 42 s dan satu klip dari foto diam dalam 3 min 20 s, keduanya dengan suara.

1. Taruh kunci Anda di `OMNIAKEY_API_KEY`.
2. POST ke `https://api.omniakey.com/v1/media/tasks` dengan model, operasi, prompt, parameter, dan `Idempotency-Key` baru.
3. Polling `GET /v1/media/tasks/{id}` sampai statusnya succeeded, lalu unduh `assets[0].url` saat itu juga.

## Apakah ada API Wan 3.0 resmi, dan model mana yang sebaiknya dipakai?

Ada. Alibaba Cloud Model Studio adalah API resminya, dengan `wan3.0-video` dan `wan3.0-video-prime` (referensi diperbarui 15 Oktober 2026). Panggilan untuk membuat tugas memerlukan header `X-DashScope-Async: enable`, dan jalur Python dari Alibaba adalah DashScope SDK 2.0.1 atau lebih baru.

||Alibaba Model Studio|OmniaKey|
|-|-|-|
|Dua ID model|Ada|Ada|
|Header async|Perlu|Tidak perlu|
|Tautan video|24 jam|Sekitar 1 jam, bisa diperbarui|
|Penagihan|Per detik|Per detik|
|Python|DashScope SDK|Pustaka standar|

Kedua ID memakai bentuk body yang sama, dan model memilih mode dari media yang Anda kirim. Skrip di bawah menjalankan `wan3.0-video`, dan baris `MODEL` menggantinya. Kami tidak menjalankan [Wan 3.0 Prime](https://omniakey.com/id/wan3-0-video-prime), yang oleh dokumentasi OmniaKey dijelaskan berkemampuan sama dengan waktu proses sekitar setengahnya (diperiksa 31 Oktober 2026).

## Apa yang perlu disiapkan sebelum panggilan pertama?

Tiga hal, dan yang pertama adalah kuncinya:

1. Kunci API OmniaKey, diekspor di shell Anda:

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

2. Python 3. Skrip hanya mengimpor pustaka standar, jadi python3 bisa menjalankannya langsung.

3. Untuk image to video, satu frame pertama: JPEG selebar sekitar 1024 px, atau URL HTTPS publik. Skrip menolak file di atas 700.000 byte, karena Base64 menambah sepertiga dan batas body 1 MiB (dokumentasi, diperiksa 31 Oktober 2026).

## Parameter mana yang penting?

Tujuh field mengerjakan sebagian besar pekerjaan, dan masing-masing adalah nilai di dalam `parameters`.

|Parameter|Fungsinya|Default|
|-|-|-|
|Durasi|Panjang klip, detik|5|
|Resolusi|Tingkat ukuran gambar|1080P|
|Rasio|Bentuk frame|adaptive|
|Audio|Trek suara|aktif|
|Seed|Petunjuk pengulangan|-1|
|Prompt extend|Menulis ulang prompt Anda|aktif|
|Watermark|Menambah tanda di sudut|mati|

Skrip menetapkan durasi, resolusi, dan rasio. Skrip meminta 720P padahal default Alibaba 1080P, yang menurut harga daftar dua kali lebih mahal per detik.

## Seperti apa kode Python-nya?

Skrip di bawah berjalan tanpa perubahan pada 31 Oktober 2026: hanya pustaka standar, dua mode, satu baris MODEL untuk diubah.

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

Yang dilakukan tiap bagian:

- `run_task` membuat `Idempotency-Key` baru untuk setiap pekerjaan. Mengirim ulang kunci yang sama dengan body yang sama mengembalikan tugas asli dan tidak menagih dua kali (dokumentasi, diperiksa 31 Oktober 2026).
- Skrip melakukan polling tiap 5 detik sampai 15 menit, lalu memunculkan TimeoutError.
- Timeout berarti polling ID yang sama nanti; kirim ulang berarti kunci baru, tugas kedua, dan ditagih.
- Skrip mengunduh URL aset pertama segera, karena tautan bertanda tangan berumur pendek.
- `image_to_video` menolak frame di atas 700.000 byte: Base64 menambah sepertiga, dan batas body 1 MiB.
- Panggilan gambar menetapkan rasio ke `adaptive`, jadi klip mengikuti bentuk foto diamnya.

Yang dicetak:

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

## Apa hasil kedua panggilan itu?

Kedua file kembali sebagai MP4 5.04 detik, 150 frame pada 30 fps, H.264, dengan trek stereo AAC 44.1 kHz.

### Text to video: tungku pandai besi

![Empat frame dari klip tungku Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-forge-grid.4c1b058b.1288.webp)

_Text to video, 5 s pada 720P: frame pada detik 0.3, 2.2, 3.5, dan 4.7._

Klipnya mengikuti prompt: pandai besi berbaju gelap dan celemek kulit menempa sepatu kuda oranye menyala, percikan muncul pada detik 2.2, dan kamera sedikit mendekat. Cacatnya adalah cap pembuat berupa huruf kacau di atas paron, padahal prompt meminta tanpa teks. Dari awal sampai jadi file 2 min 42 s; MP4-nya 1280×720 dan 6.6 MB.

### Image to video: perahu kertas

![Foto diam frame pertama dan tiga frame dari klip perahu kertas Wan 3.0](https://omniakey.com/_img/blog/wan-3-0-api/wan-paper-boat-grid.e2ffd154.1288.webp)

_Image to video: foto diam yang kami kirim (kiri atas), lalu klip pada detik 1.6, 3.5, dan 4.7._

Frame pertama adalah foto diam yang kami buat dengan Nano Banana 2.1, perahu kertas merah di genangan air hujan, diperkecil jadi JPEG 1024×571 sebesar 158 KB dan dikirim inline sebagai data URL. Klipnya mempertahankan cahaya senja dan batu jalan yang basah, menggeser perahu dari kiri ke kanan sesuai permintaan, riak pada detik 1.6, serta menjaga kamera tetap rendah dan diam. Hasilnya 1284×716 karena mode adaptive mengikuti bentuk foto diamnya, dalam 3 min 20 s pada 7.4 MB.

### Apakah suaranya aktif, dan apakah "no music" berhasil?

Suara aktif secara default. Gemini 3.8 Flash menyebut trek tungku sebagai bunyi logam berdenting tanpa ucapan dan tanpa musik, sedangkan trek perahu kertas sebagai melodi piano yang tenang dan melankolis, padahal prompt itu berakhir dengan "no music". [Panduan prompt](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide) dari Alibaba (diperbarui 16 Oktober 2026) menyarankan menulis "No BGM" atau "No background music", dan prompt kami tidak memakai keduanya.

Dengan `"audio": false` file hanya membawa trek video: pekerjaan lentera 480P 2 detik kami tidak punya trek suara, dan Alibaba menagih sama saja untuk keduanya.

|Klip|Waktu|Ukuran|Suara|
|-|-|-|-|
|Tungku (teks)|2 min 42 s|1280×720|Denting, tanpa musik|
|Perahu kertas (gambar)|3 min 20 s|1284×716|Piano meski "no music"|
|Lentera, audio mati|4 min 36 s|854×480|Tanpa trek suara|

Waktu antrean bervariasi: pekerjaan 2 detik dengan audio mati memakan 4 min 36 s, lebih lama dari kedua klip 720P 5 detik. Untuk susunan prompt, [panduan prompt Wan 3.0](https://omniakey.com/id/blog/wan-3-0-prompt-guide) memuat strukturnya dan contoh prompt.

## Bagaimana cara mengambil file videonya, dan berapa lama tautannya bertahan?

Polling `GET /v1/media/tasks/{id}` sampai statusnya berbunyi succeeded, failed, atau canceled; selama tugas berjalan statusnya queued atau processing. Tugas yang selesai mengembalikan URL aset bertanda tangan yang bertahan sekitar satu jam (dokumentasi OmniaKey, diperiksa 31 Oktober 2026). Unduh segera, lalu polling tugas itu lagi untuk URL baru ketika yang lama kedaluwarsa, karena catatannya hidup 24 jam.

File-nya MP4 dengan video H.264 pada 30 fps, dan URL video milik Alibaba sendiri bertahan 24 jam. Membatalkan pekerjaan Wan 3.0 tidak menghentikan render, dan pekerjaan yang berhasil setelah pembatalan tetap ditagih, jadi periksa durasi dan resolusi sebelum mengirim.

## Error apa yang akan Anda temui?

Sebagian besar muncul sebelum tugasnya ada, dan masing-masing punya perbaikan di permintaan atau kuncinya.

- **400 `model_price_error`** — durasi di luar 2 sampai 30 detik. Uji `"duration": 1` kami gagal dalam 0.9 s dengan "media duration must be between 2 and 30 seconds"; tidak ada tugas yang dibuat dan tidak ada tagihan.
- **400 `missing_idempotency_key`** — header Idempotency-Key tidak ada. Tambahkan satu, maksimal 255 karakter.
- **409 `idempotency_key_reused`** — kunci sama, body berbeda. Buat kunci baru untuk setiap prompt.
- **403 `model_not_allowed`** — kunci tidak boleh memanggil model itu. Periksa nilai `model`, lalu pengaturan kuncinya.
- **403 dengan pesan saldo atau batas belanja** — saldo rendah atau batas per kunci. Isi ulang atau naikkan batasnya.
- **404 `task_not_found`** — ID salah, atau tugas berumur lebih dari 24 jam. Polling ID yang dikembalikan panggilan buat tugas.
- **409 `task_state_conflict`** — pekerjaan sudah selesai, misalnya pembatalan datang setelah sukses. Baca statusnya dulu.
- **429** — terlalu banyak permintaan. OmniaKey tidak menerbitkan batas laju tetap, jadi mundur dengan jeda eksponensial dan jitter.
- **503 `no_available_channel`** — tidak ada kanal untuk operasi itu, misalnya video to video. Pakai text to video atau image to video.
- **`TimeoutError`** — masih berjalan setelah 15 menit. Polling ID yang sama nanti; kirim ulang membuat tugas kedua dan menagihnya.

## Berapa biaya satu klip Wan 3.0?

Alibaba menagih per detik video, dan permintaan yang gagal tidak ditagih (halaman harga diperbarui 29 Oktober 2026). Tabel berisi harga daftar Singapura dari Alibaba per detik, diperiksa 31 Oktober 2026, dari [halaman harga Model Studio Alibaba](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|

Menurut Alibaba, klip 720P 5 detik $0.50 di Wan 3.0 (5 × $0.1) dan $0.70 di Prime (5 × $0.14). Tiga harga Wan 3.0 membawa tanda "Limited-time 30% off", dan halaman itu tidak menyebut apakah angkanya sudah termasuk. Suara aktif atau mati biayanya sama.

Kuota gratis dari Alibaba adalah 30 detik video, input plus output, untuk `wan3.0-video` di Singapura; Prime tidak punya. Wilayah Tiongkok (Beijing) milik Alibaba mencantumkan tarif dolar yang lebih rendah untuk model standar: $0.041256, $0.082513, dan $0.165025 per detik pada 480P, 720P, dan 1080P.

OmniaKey juga menagih per detik, dengan tarif terbaru di halaman model [Wan 3.0](https://omniakey.com/id/wan3-0-video) dan [Wan 3.0 Prime](https://omniakey.com/id/wan3-0-video-prime).

## Pertanyaan yang sering diajukan

### Berapa lama satu panggilan berlangsung?

Alibaba menyebut satu pekerjaan biasanya 1 sampai 5 menit dan menyarankan polling tiap 15 detik (referensi, diperiksa 31 Oktober 2026). Tiga pekerjaan kami 2 min 42 s, 3 min 20 s, dan 4 min 36 s.

### Bagaimana cara mematikan suara?

`"audio": false` di dalam `parameters` membuat MP4 datang hanya dengan trek video, seperti pekerjaan lentera kami. Harganya tetap.

### Sebaiknya pakai wan3.0-video atau wan3.0-video-prime?

Pilih `wan3.0-video` untuk tarif daftar Alibaba yang lebih rendah dan kuota gratis 30 detik di Singapura, dan Prime ketika waktu proses lebih penting. OmniaKey menjelaskan Prime sebagai kemampuan sama dengan waktu sekitar setengahnya.

### Berapa lama tautan videonya bertahan?

Sekitar satu jam di OmniaKey, dan polling tugas itu lagi memberi tautan baru selama catatannya bertahan 24 jam. URL video milik Alibaba sendiri bertahan 24 jam.

## Sumber yang diperiksa

- [Referensi API pembuatan video Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-api-reference), diperiksa 31 Oktober 2026
- [Panduan pembuatan video Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-guide), diperiksa 31 Oktober 2026
- [Panduan prompt pembuatan video Wan 3.0](https://www.alibabacloud.com/help/en/model-studio/wan3-video-generation-prompt-guide), diperiksa 31 Oktober 2026
- [Harga model Alibaba Cloud Model Studio](https://www.alibabacloud.com/help/en/model-studio/model-pricing), diperiksa 31 Oktober 2026
- [Dokumentasi video API OmniaKey](https://docs.omniakey.com/en/media/video), diperiksa 31 Oktober 2026
- [Ikhtisar media API OmniaKey](https://docs.omniakey.com/en/media/overview), diperiksa 31 Oktober 2026
- [Kode error API OmniaKey](https://docs.omniakey.com/en/api/errors), diperiksa 31 Oktober 2026
