The Nano Banana Pro API is the same model that runs in the Gemini app, reached over HTTP instead of through a form. That is the whole proposition: an editor becomes a step in a pipeline.
Two things make the first hour harder than it should be. The model id is not something you can guess, and the response carries image bytes rather than a link.
What the API lets you automate
Anything a person can do in the app, a script can do at volume: generate from a prompt, edit an existing image, and hold references consistent across a batch. The official announcement describes text rendering in multiple languages, output at 1K, 2K or 4K, and up to 14 input images in a composition, with the exact number varying by surface.
If you have not used the model at all, read how to use Nano Banana Pro first. The prompting habits transfer directly, and a bad prompt is still a bad prompt when it arrives from a queue.
The API is also where a workflow becomes reviewable, because the prompt, the parameters and the output live in one request record.
Getting an API key and a model id
Create and store the key
The key is issued in Google’s developer console for the Gemini API, not by any third-party wrapper. Put it in an environment variable rather than in code, because a key committed to a repository is a key you have to rotate. Every request below reads it from the environment.
Which model id to pass
Here we have to be straight with you. The official API documentation page for image generation did not open when we verified this article on 2026-09-13, so we cannot print a model id as confirmed. Third-party notes repeat a preview-style string, and repeating it as fact would be worse than useless: a wrong id is a 400 on the first call.
The examples below therefore take the id from an environment variable. Copy the current string from the official model list, export it, and your code never changes when the id does.
Your first request: curl

Start with the smallest request that proves the path end to end: one text part, one image modality, nothing else. Set GEMINI_API_KEY and GEMINI_IMAGE_MODEL in your shell first.
curl -s "https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_IMAGE_MODEL}:generateContent" \
-H "x-goog-api-key: ${GEMINI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"parts": [
{ "text": "A ceramic mug on a matte grey studio surface, soft key light from the upper left, 85mm product photography, no text, no watermark." }
]
}
],
"generationConfig": { "responseModalities": ["IMAGE"] }
}' > out.json
Three things to notice. The key travels in a header, not in the URL, so it stays out of shell history and proxy logs. The prompt sits in a parts array, which is also where reference images go later. And the response lands in a file, because the image does not come back as a URL you can hand to a browser.
Read the file with a JSON parser rather than your eyes; base64 payloads are long. In the shape returned, the image arrives as inline data on a part of the first candidate, with a media type and a base64 string, while a refusal arrives as text on the same list. Walk the parts, keep the ones carrying inline data, decode, write. Confirm the exact field names against the official reference before you build on them, since we could not verify that page.
Reference images and a Python example
Multi-image work is where the API earns its place. The official announcement allows up to 14 images in a composition, and each one needs a stated role, or the model has to guess which reference it is imitating.
import base64
import json
import os
import pathlib
import urllib.request
api_key = os.environ["GEMINI_API_KEY"]
model_id = os.environ["GEMINI_IMAGE_MODEL"]
url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_id}:generateContent"
def inline_image(path: str) -> dict:
data = pathlib.Path(path).read_bytes()
return {
"inlineData": {
"mimeType": "image/png",
"data": base64.b64encode(data).decode("ascii"),
}
}
body = {
"contents": [
{
"parts": [
{
"text": (
"Reference 1 is the product: keep the object, its proportions "
"and its glaze unchanged. Reference 2 is the background style "
"only, do not copy its subject. Place the product on a light oak "
"surface with morning light from a window on the right."
)
},
inline_image("product.png"),
inline_image("background.png"),
]
}
]
}
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)
for part in payload["candidates"][0]["content"]["parts"]:
if "inlineData" in part:
pathlib.Path("out.png").write_bytes(
base64.b64decode(part["inlineData"]["data"])
)
The prompt does the load-bearing work. Each reference is labelled with what it is for, and the object is named as fixed, which is what keeps a batch from drifting image to image. For a single edit, send one reference and describe only the change.
Two habits keep this alive in production. Log the whole response body whenever a candidate comes back without inline data, because the reason is usually in the text parts. And treat the model id as configuration, not as a constant, so a rename is an environment change rather than a deployment.
Billing and quotas: what is officially published
Published, and useful for planning: output at 1K, 2K and 4K, up to 14 input images in a composition, consistency across up to five characters and fourteen objects in one workflow, and a SynthID watermark on output. Those are the capacity numbers you size a job against.
Not published on the sources we verified: a per-image price, a free quota, and rate limits. This article prints no figure for any of them, because Google has not published those numbers on the pages listed here, and a number copied from an aggregator site is that site’s rate for its own service. Check the official Gemini API pricing page before you commit to a budget.
If you are choosing between models rather than wiring one up, the Nano Banana vs GPT Image comparison sorts them by task.
Common errors and what to check first
A 400 on the first call is almost always the model id or the request body. Check the id against the official list before debugging anything else, because every example you copy from a blog may carry a stale string.
A response with text but no image is usually a content decision rather than a bug. Read the text parts before retrying, and do not loop on the same prompt expecting a different outcome.
If base64 decoding fails, you are probably decoding a text part. Filter on the inline data field instead of taking the first element of the array.
A 429 means you are sending faster than your quota allows. Since the published limits are not available to us here, the fix is measurement: log every response, find the rate that worked, and stay under it.
Do not put the key in client-side code. A browser-visible key is a public key.
Frequently asked questions
Do I need a different account for the API than for the Gemini app? The key comes from the developer console for the Gemini API. Whether your current plan covers API usage is a billing question we cannot answer from the published sources; check the official pricing page.
Can I send a reference image and a prompt in the same request? Yes, and that is the normal shape for editing. Put the text part first, describe what must not change, and label each image with its role.
How do I keep a character consistent across many calls? Send the same confirmed reference every time and repeat the identity description rather than paraphrasing it. The workflow is in the Nano Banana Pro guide.
Where did the image go in the response? Inline, as base64 on a part of the first candidate. Decode it and write it yourself, because there is no durable URL to store.
Wire up one request, log the whole response, and keep the model id in configuration. That is enough to know whether the API fits your pipeline.