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
| Parameter | Tipe | Catatan |
|---|---|---|
model | string (wajib) | Slug model video dari /v1/models. |
prompt | string (wajib) | Deskripsi teks untuk adegan. |
image_url | string | Satu gambar sumber untuk gambar-ke-video. URL atau URI data:. |
image_urls | string[] | Beberapa gambar sumber (Veo). Diutamakan daripada image_url. |
image_mode | string | Veo: "frame" (default — bingkai pertama/ |
duration | int | Durasi 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_ratio | string | misalnya "16:9", "9:16", "1:1". |
resolution | string | Jika model menyediakan tingkat kualitas — misalnya, "720p", "1080p". |
input | object | Opsi 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
| Slug | Penyedia | Catatan |
|---|---|---|
veo-3 | Veo 3.1 Fast — lebih cepat dan murah daripada Quality, audio bawaan. | |
veo-3-quality | Veo 3.1 Quality — tingkat fidelitas tertinggi. | |
veo-3-lite | Veo 3.1 Lite — tingkat hemat untuk pratinjau. | |
seedance-2-5 | ByteDance | Seedance 2.5 — klip hingga 30s, referensi multimodal, penagihan per detik. |
seedance-2 | ByteDance | Seedance 2 — konsistensi multibidik, hingga 1080p, penagihan per detik. |
seedance-2-fast | ByteDance | Seedance 2 Fast — tingkat hemat, hingga 720p, penagihan per detik. |
seedance-2-mini | ByteDance | Seedance 2.0 Mini — tingkat termurah, hanya 480p/720p, untuk draf dan produksi dalam jumlah besar. |
wan-2-7 | Alibaba | Wan 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
| Kolom | Tipe | Catatan |
|---|---|---|
id | string | ID tugas dengan awalan vid_. Stabil meski ada perubahan pada penyedia hulu. |
object | string | "video". |
status | string | queued | in_progress | completed | failed. |
model | string | Slug model yang Anda kirim. |
created_at | int | Detik Unix saat kami menerima permintaan. |
completed_at | int | null | Detik Unix saat status menjadi terminal — null selama masih tertunda. |
expires_at | int | Detik Unix, 30 hari setelah pengiriman: tugas dapat di-polling setidaknya sampai saat itu. URL hasilnya tidak kedaluwarsa. |
progress | int | 0–100. Saat ini nilainya 0 hingga tugas mencapai status akhir, lalu menjadi 100. |
output | object | null | {url, urls[], duration_ |
error | object | 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/videosmengembalikan 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/ | Asinkron /v1/videos | |
|---|---|---|
| Paling cocok untuk | Skrip sekali jalan, notebook | Produksi, perangkat seluler, tugas berdurasi panjang |
| Jaringan | Mempertahankan koneksi hingga 9 min | Kirim dalam hitungan detik; lakukan polling sesuai jadwal Anda |
| Pemulihan kegagalan | Kehilangan respons = kehilangan tugas | Kirim ulang kueri ID kapan saja sebelum expires_at |
| Konkurensi | Satu worker server per panggilan | Pengiriman langsung melepas koneksi |
| Bentuk respons | Bentuk OpenAI /images/ | Bentuk 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.