Docs

Image generation

Two endpoints: text-to-image and image edit / image-to-image. Both return result URLs that stay live for ~24 hours — download what you want to keep.

Kunavo exposes /v1/images/generations (text-to-image) and /v1/images/edits (image-to-image / edit). Behind both is the same async job runner — calls block until the upstream completes, then return result URLs.

Text-to-image

Endpoint: POST /v1/images/generations. Use the OpenAI SDK's images.generate method or curl directly.

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)

Common params

ParamTypeNotes
modelstringAny image model slug from /v1/models.
promptstringText prompt. Always required.
sizestringOpenAI-style "1024x1024". Mapped to upstream aspect-ratio.
qualitystandard|hdWhere supported (gpt-image).
resolution1K|2K|4KResolution tier for tiered models — see Resolution tiers below. Billed by tier.
nintNumber of images. Most models return 1 regardless.
inputobjectEscape hatch — see Raw input below.
Result URLs are temporary (typically 24h TTL). For production, persist the bytes to your own object storage immediately on success.

Resolution tiers

Several image models charge a stepped price by output resolution. Pass resolution to pick a tier; omit it and the default tier is used. You are billed for the tier actually produced.

Model (+ its -edit variant)Tiers — price eachDefault
nano-banana-21K $0.0469 · 2K $0.0707 · 4K $0.10571K
nano-banana-pro1K/2K $0.0938 · 4K $0.1682K
gpt-image-21K / 2K / 4K — $0.0886 (flat)1K

The veo-3 family is tiered by resolution too — per-tier prices are on each model's /models page.

GPT-Image-2 cannot render 4K at a 1:1 (square) aspect ratio. If you request resolution = 4K with a square size, the call is automatically stepped down to — and billed at — 2K.

Image edit / image-to-image

Endpoint: POST /v1/images/edits. Pass the source image as a URL (HTTPS or data: base64) via image for single-image edits, or image_urls for multi-image references.

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

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"])

Multi-image reference

Some models (Nano Banana Edit, GPT-Image-2 Edit) accept multiple reference images.

# 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",
        ],
    },
)

Supported edit models

  • nano-banana-edit — Google Nano Banana edit
  • gpt-image-2-edit — OpenAI image-to-image

Providing a source image

Image-edit and image-to-video both need a source image that the model can fetch. You have three options — pick whichever fits your app:

  • You already have a public URL — pass it straight as image (or image_url for video). Done.
  • You have a local file — upload it once via POST /v1/files, then reuse the returned permanent URL.
  • You have raw bytes in code — inline them as a data: base64 URI; Kunavo hosts them transparently.

Option A — upload via POST /v1/files

Send multipart/form-data with a file field (or JSON { "file": "data:..." }). You get back a permanent files.kunavo.com URL — files up to 25 MB.

# Upload a local file → get a permanent Kunavo URL
import requests

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 https://files.kunavo.com/... URL
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"])

Option B — inline base64

Skip the separate upload entirely: put a data: URI in the image / image_url field. Kunavo decodes it, hosts it on its CDN, and feeds the hosted URL to the model.

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

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}",
    },
)
The same applies to POST /v1/video/generations image_url accepts an https URL or a data: base64 URI for image-to-video models like Veo 3.

Response shape

Both endpoints return OpenAI's standard images response:

{
  "created": 1779360636,
  "data": [
    { "url": "https://tempfile.aiquickdraw.com/.../result.png" }
  ]
}

Latency & timeouts

Image gen typically takes 5–60 seconds depending on the model. Kunavo's server polls the upstream task for up to 240 seconds before returning a 504. Set client-side timeout accordingly:

  • Nano Banana / Nano Banana 2: usually under 10s.
  • Nano Banana Pro / GPT-Image-2: 15–60s.
  • Multi-reference + premium tier: up to ~2 minutes.

Raw input escape hatch

For per-model knobs Kunavo doesn't map (seed, guidance scale, custom resolution enums), pass input verbatim and skip our adapter.

# For full control, pass kie-style 'input' verbatim. Skips our adapter.
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",
    }},
)
When you pass input, you bypass Kunavo's validation. If the upstream rejects your fields you'll get a 422 from us — check error docs and the model's upstream documentation.

Where to go next