28 May 2026

If you're a developer who needs Nano Banana in production but doesn't want to wire up Google Cloud billing, manage IAM roles, or commit to one provider, OpenRouter is the path.
One API key, three Nano Banana model variants, transparent pay-per-call pricing, and a single SDK that also gives you Midjourney, Stable Diffusion, and dozens of other image models on the same line of code.
This guide walks through everything:
If you're not yet sure what Nano Banana is, start with our primer on what is Nano Banana and our Nano Banana beginner's guide.
Otherwise, into the API.
Four reasons developers reach for OpenRouter over the direct Google API:
Nano Banana today, switch to Midjourney or Qwen Image Edit tomorrow without rewriting your auth flow.
Skip IAM, skip GCP project creation, skip enabling billing. Just a credit card and an API key.
OpenRouter pricing is exposed in their UI. The cost per call shows up in your dashboard live.
If Google has an outage, OpenRouter can route to an alternative endpoint for some models. Useful for production resilience.
OpenRouter is not the best fit for every use case.
For 90% of indie developers, small teams, and prototypes, OpenRouter wins. For enterprise production, evaluate direct.
As of May 2026, OpenRouter offers three Nano Banana variants.

Pricing sourced from OpenRouter's official model pages, including the Gemini 3.1 Flash Image Preview page.
Each generated image is roughly 1,290 output tokens.

For 1,000 images/month:

Pick the model by your job:
For a deeper v1 vs v2 comparison for character work, read theNano Banana character consistency guide.
Go to OpenRouter, sign up with Google or GitHub, and add a payment method.
OpenRouter operates on credit balance. Top up $5 to start.
Go to:
Settings → Keys → Create New Key
Save it as an environment variable:
1export OPENROUTER_API_KEY="sk-or-v1-..."The simplest possible curl:
1curl https://openrouter.ai/api/v1/chat/completions \
2 -H "Authorization: Bearer $OPENROUTER_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "model": "google/gemini-3.1-flash-image-preview",
6 "messages": [
7 {
8 "role": "user",
9 "content": "Generate an image of a serene mountain lake at sunrise, photorealistic."
10 }
11 ],
12 "modalities": ["image", "text"]
13 }'The response includes a base64-encoded image in the assistant message. Decode and save it as a PNG.
That’s it. You’ve made your first Nano Banana 2 call.
1import os
2import base64
3import requests
4
5API_KEY = os.environ["OPENROUTER_API_KEY"]
6URL = "https://openrouter.ai/api/v1/chat/completions"
7
8def generate_image(prompt, model="google/gemini-3.1-flash-image-preview"):
9 response = requests.post(
10 URL,
11 headers={
12 "Authorization": f"Bearer {API_KEY}",
13 "Content-Type": "application/json",
14 "HTTP-Referer": "https://your-site.com", # optional, for OpenRouter analytics
15 "X-Title": "Your App Name", # optional
16 },
17 json={
18 "model": model,
19 "messages": [{"role": "user", "content": prompt}],
20 "modalities": ["image", "text"],
21 },
22 timeout=60,
23 )
24 response.raise_for_status()
25 data = response.json()
26
27 # Extract the image from the message
28 message = data["choices"][0]["message"]
29 if "images" in message:
30 for img in message["images"]:
31 b64 = img["image_url"]["url"].split(",", 1)[1]
32 return base64.b64decode(b64)
33 raise RuntimeError(f"No image in response: {data}")
34
35if __name__ == "__main__":
36 img_bytes = generate_image(
37 "A cozy Scandinavian living room with a cream bouclé sofa, "
38 "brass arc lamp, jute rug. Soft natural light from the left. "
39 "Photorealistic, magazine quality."
40 )
41 with open("output.png", "wb") as f:
42 f.write(img_bytes)
43 print("Saved output.png")1import fs from "node:fs";
2
3const API_KEY = process.env.OPENROUTER_API_KEY;
4const URL = "https://openrouter.ai/api/v1/chat/completions";
5
6async function generateImage(prompt, model = "google/gemini-3.1-flash-image-preview") {
7 const response = await fetch(URL, {
8 method: "POST",
9 headers: {
10 Authorization: `Bearer ${API_KEY}`,
11 "Content-Type": "application/json",
12 "HTTP-Referer": "https://your-site.com",
13 "X-Title": "Your App Name",
14 },
15 body: JSON.stringify({
16 model,
17 messages: [{ role: "user", content: prompt }],
18 modalities: ["image", "text"],
19 }),
20 });
21
22 if (!response.ok) {
23 throw new Error(`HTTP ${response.status}: ${await response.text()}`);
24 }
25
26 const data = await response.json();
27 const message = data.choices[0].message;
28 if (message.images && message.images.length > 0) {
29 const dataUrl = message.images[0].image_url.url;
30 const b64 = dataUrl.split(",", 2)[1];
31 return Buffer.from(b64, "base64");
32 }
33 throw new Error("No image in response");
34}
35
36const img = await generateImage(
37 "A cozy Scandinavian living room with a cream bouclé sofa, brass arc lamp, jute rug."
38);
39fs.writeFileSync("output.png", img);
40console.log("Saved output.png");The whole point of Nano Banana is editing.
Here’s how to send a reference image:
1import os, base64, requests
2from pathlib import Path
3
4API_KEY = os.environ["OPENROUTER_API_KEY"]
5
6def edit_image(reference_path, prompt, model="google/gemini-3.1-flash-image-preview"):
7 img_bytes = Path(reference_path).read_bytes()
8 b64 = base64.b64encode(img_bytes).decode()
9 data_url = f"data:image/png;base64,{b64}"
10
11 response = requests.post(
12 "https://openrouter.ai/api/v1/chat/completions",
13 headers={"Authorization": f"Bearer {API_KEY}"},
14 json={
15 "model": model,
16 "messages": [{
17 "role": "user",
18 "content": [
19 {"type": "text", "text": prompt},
20 {"type": "image_url", "image_url": {"url": data_url}},
21 ],
22 }],
23 "modalities": ["image", "text"],
24 },
25 timeout=60,
26 )
27 response.raise_for_status()
28 data = response.json()
29 message = data["choices"][0]["message"]
30 if "images" in message:
31 return base64.b64decode(message["images"][0]["image_url"]["url"].split(",", 1)[1])
32 raise RuntimeError(f"No image returned: {data}")
33
34if __name__ == "__main__":
35 edited = edit_image(
36 "room.jpg",
37 "Keeping the room layout, window position, and ceiling height the same, "
38 "replace the sofa with a low-profile bouclé sectional in cream. Photorealistic."
39 )
40 Path("edited.png").write_bytes(edited)This is the workflow that powers:
OpenRouter's rate limits are tied to your account balance, not a fixed quota.
Example:
1{
2 "model": "google/gemini-3.1-flash-image-preview",
3 "messages": [...],
4 "provider": { "order": ["Google AI Studio"] }
5}
If you're running serious volume, these patterns save real money.
Identical prompts return effectively identical images, but you still get charged.
If your app generates the same hero image for many users, generate once and serve it from S3.
Iterate cheaply. Pay for quality only on the keepers.
A draft-then-final pipeline often runs 5× cheaper than calling Pro for every iteration.
Long, verbose prompts cost real money on the input side.
A 500-word prompt vs a 100-word prompt is a 5× input cost difference.
Tight prompts are also better prompts.
For workflows that generate the same image in multiple variations, single-call multi-modal requests are sometimes cheaper than N separate requests.
Test this on your specific use case.
Sending a 12-megapixel reference image inflates input token count dramatically.
Resize to 1024×1024 before sending. Quality is identical, cost drops.
The break-even point on cost is somewhere around 50K–100K calls/month, depending on your model mix.
The model ID for Nano Banana 2 is:
1google/gemini-3.1-flash-image-previewThe original Nano Banana is:
1google/gemini-2.5-flash-imageNano Banana Pro is:
1google/gemini-3-pro-image-previewRoughly:
You can check live pricing on theOpenRouter Gemini 3.1 Flash Image Preview page.
OpenRouter gives free credits to new accounts.
That is sufficient for testing, but not enough for production. After that, top up via credit card.
Yes.
Pass the reference image as a data:image/png;base64,... URL in a multimodal user message. The code example above shows the full workflow.
At low volumes, it is roughly equivalent.
At very high volumes, around 100K+ images/month, direct Google API is cheaper.
OpenRouter's value is in flexibility and ease of setup, not absolute cost.
No.
The images themselves carry Google's invisibleSynthID watermark, which doesn't affect appearance. OpenRouter adds nothing of its own.
The image is returned in a single chunk after generation.
Meaningful streaming isn't available for image generation in the way it is for text. Set a 60-second timeout and wait.
OpenRouter is compatible with the OpenAI Python SDK.
Point the SDK to:
1OpenAI(
2 base_url="https://openrouter.ai/api/v1",
3 api_key="..."
4)Then use it normally.
Most LangChain and LlamaIndex integrations work out of the box.
The fastest way to learn this is to make the call.
Sign up, top up $5, copy the curl example, swap the prompt, and run it.
Twenty minutes from now you'll have your first generated image and a working API key.
For deeper rabbit holes once you've got the basics, read: