Dokumentasi

Dokumentasi

Pembuatan video

Teks-ke-video dan gambar-ke-video pada keluarga Google Veo 3.1. Tersedia dua bentuk API: endpoint sinkron sekali jalan yang menunggu hingga klip siap, dan pasangan endpoint asinkron untuk pengiriman dan polling, bagi beban kerja produksi.

Endpoint: POST /v1/video/generations (sinkron, dibahas terlebih dahulu), serta POST /v1/videos + GET /v1/videos/{id} (asinkron, disarankan untuk produksi). Proses pembuatan berlangsung selama 30 detik hingga beberapa menit, bergantung pada model dan durasi — untuk endpoint sinkron, atur batas waktu klien yang cukup longgar (600s aman).

Teks-ke-video

Kirim prompt dan pilih model. aspect_ratio bersifat opsional.

import requests

resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane unfolding, soft light",
        "aspect_ratio": "16:9",
    },
    timeout=600,  # video generation can take minutes
)
print(resp.json()["data"][0]["url"])

duration (dalam detik) menentukan durasi klip pada model dengan penagihan per detik: model-model Seedance dan model Wan 2.7. Model-model Veo mengabaikannya; setiap klip Veo berdurasi 8 detik dan ditagih per video.

# The models billed per second take a clip length: here 5 seconds of
# Seedance 2. Leave "duration" out and these models make a 5-second clip.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "seedance-2",
        "prompt": "a paper crane unfolds into a flock of birds over a city at dawn",
        "duration": 5,
        "aspect_ratio": "16:9",
    },
    timeout=600,
)
print(resp.json()["data"][0]["url"])

Gambar menjadi video

Tambahkan image_url, lalu Veo akan menganimasikannya — secara default, gambar diam menjadi bingkai pertama video.

# Image-to-video: animate a still image. The source image can be an
# https URL, or inline base64 — Kunavo hosts it for the model automatically.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "the crane gently lifts off the desk",
        "image_url": "https://your-cdn.com/source.png",
    },
    timeout=600,
)
print(resp.json()["data"][0]["url"])
image_url menerima URL https:// atau URI base64 data: inline. Base64 otomatis didekode dan dihosting di CDN Kunavo sebelum model dijalankan.

Bingkai pertama, bingkai terakhir, dan referensi

image_mode mengatur cara Veo menggunakan gambar. Kirim image_urls (array) untuk menyertakan lebih dari satu gambar.

  • frame (default) — satu gambar menjadi bingkai pertama; dua gambar menjadi bingkai pertama dan terakhir, lalu Veo membuat transisi di antaranya.
  • reference — hingga tiga gambar berfungsi sebagai referensi gaya dan subjek. Gambar-gambar tersebut memandu tampilan, tetapi tidak pernah muncul sebagai bingkai.
# First + last frame: pass two images and Veo fills in the motion.
resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "a smooth transition between the two poses",
        "image_urls": [
            "https://your-cdn.com/first.png",
            "https://your-cdn.com/last.png",
        ],
        "image_mode": "frame",
    },
    timeout=600,
)

Mengunggah bingkai sumber

Jika Anda hanya memiliki file lokal, unggah sekali melalui POST /v1/files dan gunakan kembali URL permanen yang dikembalikan.

# No public URL? Upload the still first, then animate it.
with open("frame.png", "rb") as f:
    up = requests.post(
        "https://api.kunavo.com/v1/files",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": f},
    ).json()

resp = requests.post(
    "https://api.kunavo.com/v1/video/generations",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "veo-3",
        "prompt": "slow push-in, volumetric light",
        "image_url": up["url"],
    },
    timeout=600,
)

Parameter

ParameterTipeCatatan
modelstring (wajib)Slug model video dari /v1/models.
promptstring (wajib)Deskripsi teks untuk adegan.
image_urlstringSatu gambar sumber untuk gambar-ke-video. URL atau URI data:.
image_urlsstring[]Beberapa gambar sumber (Veo). Diutamakan daripada image_url.
image_modestringVeo: "frame" (default — bingkai pertama/terakhir) atau "reference" (referensi gaya).
durationintDurasi klip dalam detik pada model dengan penagihan per detik, 5 jika tidak disertakan: Seedance 2, Seedance 2 Fast, dan Seedance 2.0 Mini menerima 4–15, Seedance 2.5 menerima 4–30, Wan 2.7 menerima 2–15. Durasi di luar rentang model ditolak dengan error 400. Veo mengabaikan parameter ini: setiap klip Veo berdurasi 8 detik.
aspect_ratiostringmisalnya "16:9", "9:16", "1:1".
resolutionstringJika model menyediakan tingkat kualitas — misalnya, "720p", "1080p".
inputobjectOpsi cadangan — lihat Raw input di bawah.

Opsi untuk meneruskan input mentah

Pada model dengan penagihan per detik, input dikirim ke upstream apa adanya, menggantikan input yang akan dibuat oleh adaptor kami. Model-model Veo mengabaikannya.

Field penentu harga merupakan pengecualian: resolution selalu dikirim sebagai salah satu tingkat model (tingkat bawaan jika tidak disertakan atau nilainya bukan salah satunya), dan duration harus berupa bilangan bulat dalam detik yang berada dalam rentang model (nilai lain apa pun ditolak dengan error 400; jika tidak disertakan, 5 dikirim). resolution dan duration milik permintaan itu sendiri tidak dibaca jika input ditetapkan.

Model video

SlugPenyediaCatatan
veo-3GoogleVeo 3.1 Fast — lebih cepat dan murah daripada Quality, audio bawaan.
veo-3-qualityGoogleVeo 3.1 Quality — tingkat fidelitas tertinggi.
veo-3-liteGoogleVeo 3.1 Lite — tingkat hemat untuk pratinjau.
seedance-2-5ByteDanceSeedance 2.5 — klip hingga 30s, referensi multimodal, penagihan per detik.
seedance-2ByteDanceSeedance 2 — konsistensi multibidik, hingga 1080p, penagihan per detik.
seedance-2-fastByteDanceSeedance 2 Fast — tingkat hemat, hingga 720p, penagihan per detik.
seedance-2-miniByteDanceSeedance 2.0 Mini — tingkat termurah, hanya 480p/720p, untuk draf dan produksi dalam jumlah besar.
wan-2-7AlibabaWan 2.7 — teks-ke-video sinematik, penagihan per detik.

Selalu periksa /models untuk daftar terbaru dan harga per model.

Latensi & waktu tunggu

  • Kunavo melakukan polling ke tugas penyedia hulu hingga 540 detik sebelum mengembalikan 504.
  • Tingkat cepat (Veo 3.1 Fast / Lite): sering kali 30–90 detik.
  • Tingkat kualitas dan durasi lebih panjang: 2–5 menit.
  • Atur batas waktu klien HTTP Anda minimal 600s.
  • Pada jaringan yang tidak stabil atau klien seluler, sebaiknya gunakan API asinkron — permintaan pengiriman selesai dalam hitungan detik, lalu Anda melakukan polling untuk mendapatkan hasil.

API asinkron (submit + poll)

Endpoint: POST /v1/videos + GET /v1/videos/{id}. Objek tugas yang dikembalikan menggunakan nama field dan nilai status dari objek video OpenAI, serta menambahkan output dengan URL klip. Permintaan berupa body JSON dengan parameter di atas.

Endpoint sinkron di atas mempertahankan koneksi HTTP terbuka hingga sembilan menit — praktis untuk skrip sekali jalan, tetapi tidak andal di perangkat seluler dan tidak efisien di server. Pasangan endpoint asinkron segera mengembalikan ID vid_*; Anda melakukan polling ke GET /v1/videos/{id} hingga status bernilai completed atau failed. Model, harga, dan URL arsipnya tetap sama.

import requests, time

# 1. Submit — returns immediately with a task id. No long-lived connection.
submit = requests.post(
    "https://api.kunavo.com/v1/videos",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        # Optional: retrying with the same key inside ~24h returns the
        # original task rather than submitting again.
        "Idempotency-Key": "my-task-uuid",
    },
    json={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane",
        "aspect_ratio": "16:9",
    },
    timeout=60,
).json()

task_id = submit["id"]              # "vid_abc..."
status  = submit["status"]          # "queued"

# 2. Poll until terminal. Recommended cadence: 5s, backing off to 30s.
while status not in ("completed", "failed"):
    time.sleep(5)
    r = requests.get(
        f"https://api.kunavo.com/v1/videos/{task_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=30,
    ).json()
    status = r["status"]

if status == "failed":
    raise RuntimeError(r["error"]["message"])
print(r["output"]["url"])

Dengan OpenAI SDK, kirim body tersebut dengan client.post dan lakukan polling dengan client.get, seperti di bawah ini. client.videos.create milik SDK sendiri tidak berfungsi di sini: metode tersebut hanya menerima parameter Sora dan mengirimkannya sebagai formulir multipart (di Python SDK sejak versi 2.27.0); endpoint ini menolak permintaan multipart tersebut dengan respons 400.

import time
from openai import OpenAI

client = OpenAI(api_key=API_KEY, base_url="https://api.kunavo.com/v1")

# The same JSON body, sent with the client's own post().
task = client.post(
    "/videos",
    body={
        "model": "veo-3",
        "prompt": "a cinematic dolly-in on a red origami crane",
        "aspect_ratio": "16:9",
    },
    # object hands back the JSON as parsed. Passing dict instead raises
    # after the task has been created.
    cast_to=object,
    options={"headers": {"Idempotency-Key": "my-task-uuid"}},
)

while task["status"] not in ("completed", "failed"):
    time.sleep(5)
    task = client.get(f"/videos/{task['id']}", cast_to=object)

if task["status"] == "failed":
    raise RuntimeError(task["error"]["message"])
print(task["output"]["url"])

Bentuk respons

KolomTipeCatatan
idstringID tugas dengan awalan vid_. Stabil meski ada perubahan pada penyedia hulu.
objectstring"video".
statusstringqueued | in_progress | completed | failed.
modelstringSlug model yang Anda kirim.
created_atintDetik Unix saat kami menerima permintaan.
completed_atint | nullDetik Unix saat status menjadi terminal — null selama masih tertunda.
expires_atintDetik Unix, 30 hari setelah pengiriman: tugas dapat di-polling setidaknya sampai saat itu. URL hasilnya tidak kedaluwarsa.
progressint0–100. Saat ini nilainya 0 hingga tugas mencapai status akhir, lalu menjadi 100.
outputobject | null{url, urls[], duration_seconds, resolution} saat selesai. duration_seconds adalah durasi klip yang diminta dari model, null pada Veo; resolution adalah tingkat resolusi klip, atau null jika tidak ada yang tercatat.
errorobject | null{code, message} saat gagal.

Header dan konvensi

  • Idempotency-Key (opsional, hingga 128 karakter) — pengiriman dua kali dengan kunci yang sama di akun yang sama akan mengembalikan tugas awal, bukan membuat duplikat. Berguna untuk mekanisme percobaan ulang.
  • POST /v1/videos mengembalikan 202 Accepted untuk pengiriman baru dan 200 OK saat kunci idempotensi mengulangi hasil sebelumnya.
  • GET /v1/videos/{id} dibatasi berdasarkan pemilik: kueri untuk tugas milik akun lain akan mengembalikan 404 — kami tidak pernah mengonfirmasi bahwa ID tersebut ada untuk orang lain.
  • Frekuensi polling yang disarankan: setiap 5 s dengan jeda eksponensial hingga 30 s. Tugas biasanya selesai dalam 30 s – 5 min, bergantung pada model dan resolusi.

Kapan menggunakan yang mana

Sinkron /v1/video/generationsAsinkron /v1/videos
Paling cocok untukSkrip sekali jalan, notebookProduksi, perangkat seluler, tugas berdurasi panjang
JaringanMempertahankan koneksi hingga 9 minKirim dalam hitungan detik; lakukan polling sesuai jadwal Anda
Pemulihan kegagalanKehilangan respons = kehilangan tugasKirim ulang kueri ID kapan saja sebelum expires_at
KonkurensiSatu worker server per panggilanPengiriman langsung melepas koneksi
Bentuk responsBentuk OpenAI /images/generationsBentuk OpenAI /videos

Respons dan penyimpanan

Respons mengikuti bentuk standar OpenAI — data[].url. URL tersebut adalah tautan permanen files.kunavo.com: Kunavo mengarsipkan setiap hasil ke CDN-nya sendiri, sehingga tidak seperti URL mentah dari penyedia hulu, URL ini tidak pernah kedaluwarsa. Setiap klip juga muncul di /app/assets.

Langkah selanjutnya