This article gives you four things: the correct model id, a curl and Python request you can run as written, the five parameters that return an API error if set, and a published spec table with the documented billing and latency numbers. Developer tone, short sentences, no marketing.
Nano Banana 2.1 was published on 2026-10-06 per OpenRouter and is the fourth generation of the family. It is optimized for multimodal image generation and editing. We fix the id and routes first, then give runnable code.
Model id and three access routes
The official model id is gemini-nano-banana-2.1. Google Cloud docs call it Gemini Nano Banana 2.1. That string is the model field you pass in every request; do not invent it.
Three routes. First, the official Google Gemini Developer API at generativelanguage.googleapis.com/v1beta/models/{model}:generateContent, with the key in the x-goog-api-key header. Second, OpenRouter, slug google/gemini-nano-banana-2.1. Third, fal.ai, endpoint google/nano-banana-2.1, supporting text-to-image up to 4K, adjustable aspect ratio, and optional web search grounding.
For the previous generation, read the Nano Banana Pro API guide.
Your first request: curl

Start with the smallest request that proves the path: one text part, one IMAGE modality, nothing else. Set NANO_BANANA_MODEL and GEMINI_API_KEY first.
export NANO_BANANA_MODEL=gemini-nano-banana-2.1
curl -s "https://generativelanguage.googleapis.com/v1beta/models/${NANO_BANANA_MODEL}:generateContent" \
-H "x-goog-api-key: ${GEMINI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"parts": [
{ "text": "A matte ceramic water bottle on a round studio pedestal, soft diffused light, photorealistic product photography, no text, no watermark." }
]
}
],
"generationConfig": { "responseModalities": ["IMAGE"] }
}' > out.json
The key travels in the header, not the URL. The prompt sits in the parts array. The response lands in a file, because the image is inline data, not a URL.
Read it with a JSON parser, since base64 is long. In the returned shape, the image is inline data on a part of the first candidate; a refusal shows up as text in the same parts list. Confirm the field names against the official reference, since we could not test a live key call. Keep the key in an environment variable, never in code.
Fetch the image with Python
This snippet re-runs the request and decodes the image to disk.
import base64
import json
import os
import pathlib
import urllib.request
api_key = os.environ["GEMINI_API_KEY"]
model_id = os.environ["NANO_BANANA_MODEL"]
url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_id}:generateContent"
body = {
"contents": [
{
"parts": [
{
"text": "A matte ceramic water bottle on a round studio pedestal, soft diffused light, photorealistic product photography, no text, no watermark."
}
]
}
],
"generationConfig": {"responseModalities": ["IMAGE"]},
}
request = urllib.request.Request(
url,
data=json.dumps(body).encode("utf-8"),
headers={"x-goog-api-key": api_key, "Content-Type": "application/json"},
)
with urllib.request.urlopen(request) as response:
payload = json.load(response)
out_dir = pathlib.Path("out")
out_dir.mkdir(exist_ok=True)
saved = 0
for candidate in payload.get("candidates", []):
for part in candidate.get("content", {}).get("parts", []):
inline = part.get("inlineData")
if inline:
out_dir.joinpath(f"image-{saved}.png").write_bytes(
base64.b64decode(inline["data"])
)
saved += 1
print(f"saved {saved} image(s)")
The loop keeps only parts with inlineData and skips text, so a refusal is never decoded as an image. Prompt quality drives the output, so read the Nano Banana Pro prompt guide first.
Log the whole response when a candidate lacks inlineData. Treat the model id as configuration, not a constant.
Five parameters Google rejects
The official docs state plainly that Nano Banana 2.1 does not support seed, topK, logprobs, temperature, or topP, and setting any returns an API error.
{
"generationConfig": {
"responseModalities": ["IMAGE"],
"temperature": 0.7
}
}
These are the sampling and randomness controls common to text models. An image model on a different path rejects them. Rule of thumb: keep only responseModalities in generationConfig and write no other sampling parameter. No equivalent switch is documented. Drop temperature and the request works.
If you are migrating a call from a text model, delete the whole sampling block rather than trimming it. Randomness, top-k truncation and log-probabilities all sit on the rejected list, and there is no image-side equivalent to switch on. Batches that must be reproducible cannot pin a seed here either, so treat variation as a review step, not a parameter you control.
Specs and limits
The table collects the specs the official docs publish. Anything beyond it that we cannot confirm is treated as not officially published.
| Item | Value |
|---|---|
| Context window | 131,072 tokens |
| Max output tokens | 32,768 |
| Max input images per prompt | 14 |
| Output resolution | 1K / 2K / 4K |
| Aspect ratios | 15: 1:1, 3:2, 2:3, 3:4, 1:4, 4:1, 4:3, 4:5, 5:4, 1:8, 8:1, 9:16, 16:9, 21:9, 9:21 |
| Input size limit | 500 MB |
| Direct upload | 7 MB |
| Cloud Storage | 30 MB per file |
| Supported MIME | image/png, image/jpeg, image/webp, image/heic, image/heif |
| Content credentials | C2PA Content Credentials supported |
| Batch and throughput | pay-as-you-go, Batch inference, Provisioned throughput; fixed quota not supported |
The docs also list multi-turn editing, video input to image, interleaved text and image, Google and image search grounding, thinking and system instructions; structured output is not supported.
Two limits shape a real pipeline. The MIME list means phone HEIC files are accepted, but convert them when the rest of your stack expects PNG or WebP. The upload ceiling is 7 MB inline, so route anything larger through Cloud Storage, where a single file may reach 30 MB.
Billing and latency numbers
Google docs give no specific price, only that the value is good, so rely on the Nano Banana Pro pricing page.
OpenRouter lists input $1.50 and output $30.00 per 1M tokens, blended around $23.01 (OpenRouter numbers, not Google prices). Its panel reports end-to-end latency P50 about 19.64 seconds, 3-day uptime 99.83% and availability 87.90% (OpenRouter three-day measurements, not a Google guarantee).
Usage options: pay-as-you-go, Batch inference, Provisioned throughput; fixed quota is not supported.
Read the latency as a planning number. A P50 near twenty seconds means roughly one image per worker per twenty seconds, so parallelize at the queue level instead of hoping for faster single calls. The gap between uptime and availability also matters: the endpoint was reachable almost always, but inference errors and empty responses pull availability to near 88 percent, which is why a retry policy belongs in the client.
FAQ
Which model id? gemini-nano-banana-2.1. Google docs, OpenRouter slug, and fal.ai endpoint all point to it. Copy the whole string.
Why does temperature error? The docs say it is unsupported, with seed, topK, logprobs, topP; setting any returns an error. Keep only responseModalities in generationConfig.
How much? Google gives no price, only good value; use the official pricing page. OpenRouter: input $1.50, output $30.00 per 1M, blended ~$23.01. OpenRouter numbers, not Google.
Latency? OpenRouter three-day: P50 ~19.64s, uptime 99.83%, availability 87.90%. Measurements, not a Google commitment.
Start from the Nano Banana Pro how-to-use guide. Put the id in an env var, get one request working, log the response.