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
| Param | Type | Notes |
|---|---|---|
model | string | Any image model slug from /v1/models. |
prompt | string | Text prompt. Always required. |
size | string | OpenAI-style "1024x1024". Mapped to upstream aspect-ratio. |
quality | standard|hd | Where supported (gpt-image). |
resolution | 1K|2K|4K | Resolution tier for tiered models — see Resolution tiers below. Billed by tier. |
n | int | Number of images. Most models return 1 regardless. |
input | object | Escape hatch — see Raw input below. |
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 each | Default |
|---|---|---|
| nano-banana-2 | 1K $0.0469 · 2K $0.0707 · 4K $0.1057 | 1K |
| nano-banana-pro | 1K/2K $0.0938 · 4K $0.168 | 2K |
| gpt-image-2 | 1K / 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.
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 editgpt-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(orimage_urlfor 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}",
},
)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",
}},
)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.