Dokumentasi

Dokumentasi

Pembuatan gambar

Dua endpoint: teks ke gambar dan penyuntingan gambar / gambar ke gambar. Keduanya mengembalikan URL hasil yang permanen: Kunavo mengarsipkan setiap gambar ke CDN-nya sendiri.

Kunavo menyediakan /v1/images/generations (teks ke gambar) dan /v1/images/edits (gambar ke gambar / penyuntingan). Keduanya berjalan secara sinkron secara default — panggilan menunggu hingga proses upstream selesai, lalu mengembalikan URL hasil — atau gunakan mode asinkron dengan "async": true atau webhook_url.

Teks ke gambar

Endpoint: POST /v1/images/generations. Gunakan metode images.generate pada OpenAI SDK atau langsung dengan curl.

img = client.images.generate(
    model="nano-banana-pro",
    prompt="a red origami crane on a white desk, soft window light",
    size="1024x1024",
)
print(img.data[0].url)

/v1/images/generations tidak menerima gambar apa pun: permintaan yang menyertakan gambar (image, image_url, atau image_urls) ditolak dengan error 400. Untuk menyunting gambar, kirim gambar tersebut ke /v1/images/edits.

Parameter umum

ParameterTipeCatatan
modelstringSlug model gambar apa pun dari /v1/models.
promptstringPrompt teks. Selalu wajib diisi.
sizestringFormat bergaya OpenAI, "1024x1024". Dipetakan ke rasio aspek upstream.
qualitystandard|hdJika didukung (gpt-image).
resolution1K|2K|4KTingkat resolusi untuk model bertingkat — lihat Resolution tiers di bawah. Biaya dihitung berdasarkan tingkat.
nintJumlah gambar. Sebagian besar model selalu mengembalikan 1.
inputobjectOpsi cadangan — lihat Raw input di bawah.
URL hasil adalah tautan permanen files.kunavo.com: Kunavo mengarsipkan setiap gambar ke CDN-nya sendiri, sehingga tidak seperti URL mentah dari penyedia hulu, URL ini tidak pernah kedaluwarsa. Jika sebuah gambar tidak dapat diarsipkan, URL-nya adalah URL sementara dari penyedia hulu di host lain: unduh gambar tersebut dan host ulang.

Tingkat resolusi

Beberapa model gambar mengenakan harga bertingkat berdasarkan resolusi keluaran. Berikan resolution untuk memilih tingkat; jika dihilangkan, tingkat bawaan akan digunakan. Biaya dihitung berdasarkan tingkat yang benar-benar dihasilkan.

Model (beserta variannya -edit)Tingkat — harga masing-masingBawaan
nano-banana-21K $0.0469 · 2K $0.0707 · 4K $0.10571K
nano-banana-pro1K / 2K $0.067 · 4K $0.122K
gpt-image-21K / 2K / 4K — $0.0633 (tetap)1K

Keluarga veo-3 juga memiliki tingkat resolusi — harga per tingkat tercantum di halaman /models masing-masing model.

GET /v1/models mengembalikan tingkat setiap model dalam field kunavo.tiers: harga yang tercantum untuk setiap tingkat, serta tingkat yang digunakan suatu permintaan jika permintaan itu tidak menyebutkan tingkat.

Nilai resolution yang bukan salah satu tingkat model ditolak dengan error 400, begitu pula resolution yang dikirim ke model tanpa tingkat resolusi.

GPT-Image-2 tidak tersedia dalam resolusi 4K dengan rasio aspek 1:1 (persegi). Permintaan untuk resolution = 4K ditolak dengan error 400 jika ukurannya persegi atau jika permintaan tersebut tidak menentukan ukuran apa pun. Minta 2K, atau tentukan ukuran dengan rasio aspek lain.

Penyuntingan gambar / gambar ke gambar

Endpoint: POST /v1/images/edits. Berikan gambar sumber sebagai URL (HTTPS atau base64 data:) melalui image untuk penyuntingan satu gambar, atau image_urls untuk referensi multi-gambar.

# Image edit / image-to-image: pass the source image URL
import os

import requests

API_KEY = os.environ["KUNAVO_API_KEY"]

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue, keep composition",
        "image": "https://your-cdn.com/source.png",
    },
)
print(resp.json()["data"][0]["url"])

Referensi multi-gambar

Beberapa model (Nano Banana Edit, GPT-Image-2 Edit) menerima beberapa gambar referensi.

# nano-banana-edit accepts multiple reference images
resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "nano-banana-edit",
        "prompt": "merge subject from img1 with background from img2",
        "image_urls": [
            "https://your-cdn.com/subject.png",
            "https://your-cdn.com/background.png",
        ],
    },
)

Model yang menerima beberapa gambar mencantumkan multi-image-input di GET /v1/models, dan max_input_images model tersebut adalah jumlah maksimum gambar yang boleh dikirim dalam satu permintaan. Model lain menyunting satu gambar. Permintaan yang mengirim lebih banyak gambar daripada yang diterima modelnya ditolak dengan error 400.

Masker pengisian area gambar (inpainting)

Model penyuntingan yang capabilities-nya mencakup inpainting juga menerima mask: gambar masker yang diberikan seperti gambar sumber, sebagai URL HTTPS atau data base64 data:. Masker yang dikirim ke model penyuntingan lain ditolak dengan status 400, begitu pula masker yang tidak dapat dibaca Kunavo.

Model penyuntingan yang didukung

  • nano-banana-edit — penyuntingan Google Nano Banana
  • gpt-image-2-edit — gambar ke gambar OpenAI

Memberikan gambar sumber

Penyuntingan gambar dan gambar ke video sama-sama memerlukan gambar sumber yang dapat diambil oleh model. Ada tiga opsi — pilih yang sesuai dengan aplikasi Anda:

  • Anda sudah memiliki URL publik — berikan langsung sebagai image (atau image_url untuk video). Selesai.
  • Anda memiliki file lokal — unggah sekali melalui POST /v1/files, lalu gunakan kembali URL permanen yang dikembalikan.
  • Anda memiliki byte mentah di dalam kode — sertakan secara langsung sebagai URI base64 data:; Kunavo menghostingnya secara transparan.

Opsi A — unggah melalui POST /v1/files

Kirim multipart/form-data dengan field file (atau JSON { "file": "data:..." }). Anda akan menerima URL permanen https — untuk file hingga 25 MB.

# Upload a local file → get a permanent public URL
import os

import requests

API_KEY = os.environ["KUNAVO_API_KEY"]

with open("source.png", "rb") as f:
    up = requests.post(
        "https://api.kunavo.com/v1/files",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": f},
    ).json()

# up["url"] is now a permanent public URL for the image
edit = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": up["url"],
    },
).json()
print(edit["data"][0]["url"])

Opsi B — sertakan base64 secara langsung

Lewati proses unggah terpisah: masukkan URI data: di field image / image_url. Kunavo mendekodenya, menghostingnya di CDN, lalu memberikan URL yang dihosting tersebut kepada model.

# Or skip the upload step — pass base64 inline, we host it for you.
import base64
import os

import requests

API_KEY = os.environ["KUNAVO_API_KEY"]

with open("source.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": f"data:image/png;base64,{b64}",
    },
)
Hal yang sama berlaku untuk POST /v1/video/generations — image_url menerima URL https atau URI base64 data: untuk model gambar ke video seperti Veo.

Bentuk respons

Kedua endpoint mengembalikan respons gambar standar OpenAI:

{
  "created": 1779360636,
  "data": [
    { "url": "https://files.kunavo.com/image/.../result.png" }
  ]
}

Latensi & waktu tunggu

Pembuatan gambar biasanya memerlukan waktu 5–60 detik, bergantung pada model. Dalam mode sinkron bawaan, Kunavo mempertahankan koneksi dan melakukan polling ke upstream hingga 540 detik sebelum mengembalikan 504. Atur waktu tunggu sisi klien Anda sesuai kebutuhan — atau gunakan API asinkron untuk mengirimkan permintaan dalam hitungan detik dan melakukan polling sesuai jadwal Anda sendiri:

  • Nano Banana / Nano Banana 2: biasanya kurang dari 10 detik.
  • Nano Banana Pro / GPT-Image-2: 15–60 detik.
  • Referensi multi-gambar + tingkat premium: hingga sekitar 2 menit.

Fungsi fetch bawaan Node berhenti menunggu header respons setelah 300 detik, berapa pun batas waktu yang Anda atur: di Node, gunakan API asinkron, atau panggil fungsi fetch dari paket undici dengan opsi dispatcher: new Agent({ headersTimeout: 600_000 }).

API asinkron (kirim + polling / webhook)

Kedua endpoint gambar berjalan secara sinkron secara default — panggilan mempertahankan koneksi hingga proses upstream menghasilkan gambar, lalu mengembalikan respons gambar standar OpenAI. Untuk pekerjaan batch, tingkat premium yang lambat, atau pemanggil serverless yang tidak dapat mempertahankan permintaan lama, tambahkan "async": true (atau webhook_url) ke /v1/images/generations atau /v1/images/edits.

Pengiriman mengembalikan ID img_* segera; lakukan polling pada GET /v1/images/{id} hingga status bernilai completed atau failed — atau daftarkan webhook dan lewati polling sepenuhnya.

# Async: add "async": true (or a webhook_url) to either image endpoint.
# The call returns instantly with an img_ id instead of holding the connection.
import os
import time

import requests

API_KEY = os.environ["KUNAVO_API_KEY"]
API = "https://api.kunavo.com/v1"
H = {"Authorization": f"Bearer {API_KEY}"}

submit = requests.post(
    f"{API}/images/generations",
    headers=H,
    json={"model": "gpt-image-2", "prompt": "a red panda", "async": True},
).json()

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

# Poll GET /v1/images/{id} until terminal — or skip polling and use a webhook.
while status not in ("completed", "failed"):
    time.sleep(3)
    r = requests.get(f"{API}/images/{task_id}", headers=H).json()
    status = r["status"]

if status == "completed":
    print(r["output"]["url"])
else:
    print("failed:", r["error"])

Objek tugas

KolomTipeCatatan
idstringID tugas img_* — teruskan ke GET /v1/images/{id}.
statusstringqueued | in_progress | completed | failed.
outputobject|nullSaat selesai: { url, urls, archived }. archived bernilai false jika sebuah gambar tidak dapat diarsipkan dan URL-nya adalah URL sementara dari penyedia hulu.
errorobject|nullSaat gagal: { code, message }.
expires_atint|nullDetik Unix, 30 hari setelah pengiriman: tugas dapat di-polling setidaknya sampai saat itu. URL hasilnya tidak kedaluwarsa.
GET /v1/images/{id} dibatasi berdasarkan pemilik: jika Anda meminta ID yang bukan milik Anda, hasilnya 404 dan tidak dapat dibedakan dari ID yang tidak pernah diterbitkan. Jadwal polling yang disarankan: 3 detik dengan jeda eksponensial hingga sekitar 30 detik.

Mencoba ulang dengan aman

Pada permintaan dengan "async": true atau webhook_url, kedua endpoint gambar membaca header Idempotency-Key yang panjangnya hingga 128 karakter. Permintaan yang dikirim ulang dengan kunci yang sama akan mendapatkan tugas yang dibuat oleh permintaan pertama, bukan gambar kedua, selama tugas tersebut masih dapat diambil: setidaknya 30 hari.

Tugas yang gagal tetap menjadi respons untuk kunci idempotensinya: untuk mencoba ulang, kirim permintaan dengan kunci idempotensi baru. Permintaan tanpa "async": true maupun webhook_url tidak mengembalikan tugas yang dapat ditemukan oleh pengiriman ulang, sehingga kunci idempotensi yang dikirim bersama permintaan tersebut ditolak dengan error 400.

  • Satu kunci idempotensi mewakili satu permintaan: kunci yang sudah digunakan untuk memulai tugas di endpoint lain, untuk model lain, atau untuk permintaan yang prompt atau parameternya berbeda ditolak dengan error 400. Begitu pula dengan kunci yang panjangnya lebih dari 128 karakter dan kunci yang dikirim bersama permintaan sinkron. URL gambar tidak dibandingkan: permintaan dengan URL yang ditandatangani ulang tetap merupakan permintaan yang sama.

Webhook

Berikan webhook_url (https) saat pengiriman, dan Kunavo akan mengirimkan peristiwa image.completed / image.failed bertanda tangan melalui POST saat tugas berakhir — dengan amplop dan tanda tangan yang sama seperti webhook video dan musik:

  • X-Kunavo-Webhook-Id — ID peristiwa stabil, sama pada setiap percobaan ulang (gunakan untuk deduplikasi).
  • X-Kunavo-Webhook-Timestamp — waktu Unix dalam detik saat tanda tangan dihitung.
  • X-Kunavo-Webhook-Signature — HMAC-SHA256 sha256= atas {timestamp}.{rawBody}, menggunakan rahasia webhook Anda sebagai kunci.

Jika webhook_url bukan URL https, atau berisi nama pengguna atau kata sandi, permintaan ditolak dengan error 400, dan tidak ada yang dibuat maupun ditagih.

Rahasia webhook Anda ada di dasbor, di bagian Pengaturan → Webhooks. Awalannya adalah kwh_, dan rahasia yang sama digunakan untuk menandatangani setiap peristiwa gambar, video, dan musik di akun Anda. Anda dapat menggantinya di sana; setiap peristiwa yang dikirim setelah penggantian, termasuk percobaan ulang, ditandatangani dengan rahasia baru.

Pengiriman dicoba ulang dengan jeda eksponensial selama sekitar 9 jam. Baris asinkron tetap bisa dipolling selama itu, sehingga webhook yang terlewat selalu dapat dipulihkan melalui GET.

Opsi untuk meneruskan input mentah

Untuk parameter khusus per model yang tidak dipetakan Kunavo (seed, prompt negatif, format output), teruskan input. Nilainya akan dikirim ke upstream apa adanya, menggantikan input yang akan dibuat oleh adaptor kami.

Field yang memilih tingkat harga model merupakan pengecualian: resolution, atau rendering_speed untuk Ideogram. Pada model yang memiliki beberapa tingkat, field ini selalu dikirim sebagai salah satu tingkat model tersebut, dan Anda dikenai biaya sesuai tingkat itu. Jika input tidak menyertakannya atau memberikan nilai yang bukan salah satu tingkat model, tingkat bawaan akan dikirim dan Anda dikenai biaya sesuai tingkat tersebut. Field yang sama di level teratas permintaan tidak dibaca jika input ditetapkan.

# Raw upstream 'input': sent as written, in place of what our adapter builds.
# "resolution" sets the billed tier: 2K here, the default tier when left out.
resp = client.images.generate(
    model="nano-banana-2",
    prompt="",  # ignored when input is set
    extra_body={"input": {
        "prompt": "a futuristic cyberpunk skyline at dusk",
        "aspect_ratio": "16:9",
        "resolution": "2K",
        "output_format": "png",
    }},
)
Saat Anda memberikan input, Anda melewati validasi Kunavo. Jika upstream menolak field Anda, kami akan mengembalikan 422 — periksa dokumentasi error dan dokumentasi upstream model tersebut.

Langkah selanjutnya