
Nano-Banana-2-Lite is the budget tier of the Nano-Banana image model family on hiapi: same task-based workflow as its bigger siblings, a smaller price per image, and support for both text-to-image and reference-image editing. This guide walks through a complete, working integration — create a task, poll it, download the result — in curl and Python, plus the schema details that differ from Nano-Banana-2 and Nano-Banana-Pro.
Goal: send a prompt to Nano-Banana-2-Lite, wait for the image, and save it to disk.
You need one thing: a hiapi API key (sk-...). Grab it from your hiapi dashboard. Per-image cost is listed on the pricing page and the Nano Banana 2 Lite model page.
All image models on hiapi run through the unified async task API: you POST /v1/tasks to create a job, then either poll GET /v1/tasks/{id} or receive a webhook when it finishes.
Create the task:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Nano-Banana-2-Lite",
"input": {
"prompt": "A watercolor illustration of a lighthouse at dawn, soft pastel palette",
"aspect_ratio": "3:2"
}
}'
The response contains a task id at data.taskId. Poll it:
curl -s https://api.hiapi.ai/v1/tasks/YOUR_TASK_ID \
-H "Authorization: Bearer sk-YOUR_KEY"
When data.status is "success", the image URL is at data.output[0].url. Download it right away — output URLs are signed and carry an expiry (expireAt), so store the bytes, not the link.
Two schema rules that trip people up, straight from the API's own validation:
"model": "nano-banana-2-lite" returns 400 MODEL_UNAVAILABLE ("model not available via /v1/tasks"). Use the exact id Nano-Banana-2-Lite.prompt and aspect_ratio are required. Omit either and you get 400 INVALID_REQUEST with a missing required field message. Valid aspect_ratio values: auto, 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:4, 4:1, 1:8, 8:1.No SDK required — the task API is plain JSON over HTTPS:
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
}
# 1. Create the task
resp = requests.post(
f"{API_BASE}/tasks",
headers=HEADERS,
json={
"model": "Nano-Banana-2-Lite",
"input": {
"prompt": "A watercolor illustration of a lighthouse at dawn, soft pastel palette",
"aspect_ratio": "3:2",
},
},
timeout=60,
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
print("task created:", task_id)
# 2. Poll until the task reaches a terminal state
deadline = time.time() + 600
while time.time() < deadline:
task = requests.get(
f"{API_BASE}/tasks/{task_id}", headers=HEADERS, timeout=30
).json()["data"]
if task["status"] == "success":
break
if task["status"] == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
time.sleep(3)
else:
raise TimeoutError(f"task {task_id} did not finish in 10 minutes")
# 3. Download immediately — output URLs are signed and expire
image_url = task["output"][0]["url"]
with open("lighthouse.png", "wb") as f:
f.write(requests.get(image_url, timeout=120).content)
print("saved lighthouse.png")
image_urls, not image_inputNano-Banana-2-Lite supports image editing, but its reference-image field is image_urls — an array of up to 10 publicly reachable URLs:
{
"model": "Nano-Banana-2-Lite",
"input": {
"prompt": "Replace the background with a clean white studio backdrop, keep the product unchanged",
"aspect_ratio": "auto",
"image_urls": ["https://your-cdn.com/product-photo.jpg"]
}
}
This is the family's biggest gotcha: Nano-Banana-2 and Nano-Banana-Pro use image_input for the same purpose, and Lite rejects that field (additional properties 'image_input' not allowed). Field names like input_urls, images, or reference_images are rejected on all three. If you're porting code between tiers, this one field rename is usually the only change you need.
| Nano-Banana-2-Lite | Nano-Banana-2 | Nano-Banana-Pro | |
|---|---|---|---|
| Required input | prompt, aspect_ratio | prompt | prompt |
| Reference images | image_urls (≤10) | image_input | image_input |
resolution control | not accepted | accepted | accepted |
Lite keeps the surface minimal: prompt, aspect ratio, optional reference images. There is no resolution, seed, n, or negative_prompt — sending any of them fails validation with additional properties ... not allowed. If you need explicit resolution control (1K/2K/4K) or the higher-fidelity tiers, step up to Nano-Banana-2 or Nano-Banana-Pro; if you're generating at volume — thumbnails, drafts, iteration loops, bulk variants — Lite's lower per-image cost is the point.
Use webhooks instead of polling when you can. Add a callback block when creating the task and hiapi will POST the terminal result to your endpoint:
{
"model": "Nano-Banana-2-Lite",
"input": { "prompt": "...", "aspect_ratio": "1:1" },
"callback": { "url": "https://your-app.com/webhooks/hiapi", "when": "final" }
}
when accepts only "final" — you get exactly one callback, on success or failure. Polling is fine for scripts and notebooks; callbacks are better for servers because they free you from managing poll loops and timeouts. If you do poll, a 2–5 second interval with a hard deadline (as in the Python example) is plenty.
Handle the two error layers. Request-level failures come back as HTTP errors — an invalid or unauthorized key returns 401 with {"error": {"code": "permission_denied", "type": "hiapi_error", ...}}, and schema mistakes return 400 INVALID_REQUEST with a precise validation message. Task-level failures arrive with status: "fail" and an error object on the task itself; treat both paths in your code.
Make retries idempotent. Task creation is not idempotent — retrying a timed-out create may produce two tasks (and two charges). Persist the taskId as soon as you receive it, and on restart resume polling existing ids instead of blindly re-creating.
Store bytes, not URLs. Output URLs expire. Download the image and put it in your own storage before you do anything else with it.
Why do I get "model not available via /v1/tasks"?
The model id is case-sensitive. Use Nano-Banana-2-Lite exactly; lowercase variants are rejected with 400 MODEL_UNAVAILABLE.
Does Nano-Banana-2-Lite support image-to-image editing?
Yes. Pass reference images in the image_urls array (up to 10 URLs). It handles background swaps, style transfer, and edit-by-instruction workflows driven by the prompt.
Why does my Nano-Banana-2 code fail on Lite with "additional properties 'image_input' not allowed"?
The tiers use different reference-image field names: Lite expects image_urls, while Nano-Banana-2 and Pro expect image_input. Rename the field when switching tiers.
Can I set resolution, seed, or the number of images?
Not on Lite — its input schema accepts only prompt, aspect_ratio, and image_urls. For 1K/2K/4K resolution control, use Nano-Banana-2 or Nano-Banana-Pro.
How long are output image URLs valid?
They are signed URLs with an expiry timestamp (expireAt in the output object). Download the bytes immediately and store them in your own storage; never hot-link the task output.
What does a 401 permission_denied mean?
Your API key is invalid, or it isn't allowed to use this model. Check the key in your dashboard, and make sure you're sending it as Authorization: Bearer sk-....
How much does Nano-Banana-2-Lite cost per image? It's usage-based, billed per image, and positioned as the lowest-cost tier in the Nano-Banana family. Current rates are on the pricing page.
Key Takeaways