Nano Banana 2.1 API: your first image in five minutes
Make your first Nano Banana 2.1 image: an API key, one POST request, and polling. curl, Python, and Node.js examples, three resolutions, and aspect ratios.
Rendergrid editorsAbout the editors
In brief
To make your first image with Nano Banana 2.1, you need an API key and a topped-up balance. Then you send one POST request with a model and a prompt, take the task ID from the 202 response, and poll the task until its status is completed.
The five minutes in the title are the time to follow this guide once you have a key and a balance. Signing up and topping up come first, and nothing here promises how long an image takes.
What do you need before the first request?
The order is fixed: create a key, top up, then generate. You need four things.
- An API key. Create it in the portal, under API keys. A key starts with
rg_live_and is shown in full only once, so copy it right away. See the keys page. - A balance. You top up in USDT, on the portal’s balance page or through an account manager; the API has no top-up method. A USDT payment has its own window of 30–50 minutes, so top up before you start the five minutes. See the top-up guide.
- The key in an environment variable. Set
RENDERGRID_API_KEYon your server and read it from there, so the key stays out of your code and out of any website or mobile app. - A way to send HTTPS requests. The examples use curl, Python with the
requestspackage, and Node.js 22 or newer.
Every request is a real one: it is charged when it is accepted and refunded automatically if it fails.
How do you send the first request?
A request is one POST to /api/public/v1/images/generate on api.rendergrid.io. model and prompt are required; the prompt can be up to 20,000 characters. resolution and aspect_ratio are optional, but the examples set both, so you know the tier you pay for and the shape you get.
Send the key in an Authorization: Bearer header, and a new X-Idempotency-Key for every new image. The prompt below made the three images further down.
# Requires bash, curl and uuidgen. One idempotency key per request. IDEMPOTENCY_KEY="$(uuidgen)" || exit 1 curl --fail-with-body --max-time 30 \ -X POST https://api.rendergrid.io/ api/ public/ v1/ images/ generate \ -H "Authorization: Bearer $RENDERGRID_API_KEY" \ -H "Content-Type: application/json" \ -H "X-Idempotency-Key: $IDEMPOTENCY_KEY" \ -d '{ "model": "nano-banana-2.1", "prompt": "A closed linen-covered notebook, a wooden pencil and a white ceramic cup sit on a pale desk. View them from slightly above, keeping all three within a central arrangement and leaving even margins. Soft window light from the left reveals the cloth weave, wood grain and glazed ceramic. No lettering, logos, people, or watermarks.", "resolution": "1K", "aspect_ratio": "1:1" }'
import os import uuid import requests key = os.environ["RENDERGRID_API_KEY"] PROMPT = "A closed linen-covered notebook, a wooden pencil and a white ceramic cup sit on a pale desk. View them from slightly above, keeping all three within a central arrangement and leaving even margins. Soft window light from the left reveals the cloth weave, wood grain and glazed ceramic. No lettering, logos, people, or watermarks." response = requests.post( "https://api.rendergrid.io/ api/ public/ v1/ images/ generate", headers={ "Authorization": f"Bearer {key}", # a new key for every new image; the same key when you repeat a request "X-Idempotency-Key": str(uuid.uuid4()), }, json={ "model": "nano-banana-2.1", "prompt": PROMPT, "resolution": "1K", "aspect_ratio": "1:1", }, timeout=(10, 120), ) response.raise_for_status() creation = response.json() print(creation["id"], creation["status"], creation["cost"])
// Node.js 22+, .mjs file import { randomUUID } from "node:crypto"; const API = "https://api.rendergrid.io/ api/ public/ v1"; const prompt = "A closed linen-covered notebook, a wooden pencil and a white ceramic cup sit on a pale desk. View them from slightly above, keeping all three within a central arrangement and leaving even margins. Soft window light from the left reveals the cloth weave, wood grain and glazed ceramic. No lettering, logos, people, or watermarks."; const response = await fetch(`${API}/images/generate`, { method: "POST", headers: { Authorization: `Bearer ${process.env.RENDERGRID_API_KEY}`, "Content-Type": "application/json", // a new key for every new image; the same key when you repeat a request "X-Idempotency-Key": randomUUID(), }, body: JSON.stringify({ model: "nano-banana-2.1", prompt, resolution: "1K", aspect_ratio: "1:1", }), signal: AbortSignal.timeout(120_000), }); if (response.status !== 202) { throw new Error(`HTTP ${response.status}: ${await response.text()}`); } const creation = await response.json(); console.log(creation.id, creation.status, creation.cost);
The response is 202 Accepted: the request was accepted, not finished. Its body has exactly four fields, id, status, task_id, and cost. Keep the id: it is the task ID you check next. cost is the amount, in US dollars, charged for the image.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "queued",
"task_id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"cost": 0.02
}
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "completed",
"result_urls": [
"https:// …"
]
}
Use a new key for each new image, and repeat a key only to retry the same request: you get the same 202 response, with the same id and cost, and no second charge. That saved response may still say queued after the image is ready, so take the current state from the status request.
How do you check the status and get the result?
Ask for the task with GET /api/public/v1/creations/{id}, using the id from the 202 response. The status is queued, processing, completed, or failed. While it is queued or processing, wait and ask again. completed and failed are final, so stop there.
A completed task carries result_urls, the links to the image files. A failed task carries error and failure, which has type, code, and retryable.
For one task and one key, poll no more often than once every 5 seconds; faster polling gets 429 with ERR_RATE_LIMIT. There is no promised time for a task: it depends on the model and the load. Limit your own wait, and keep the ID if it runs out: your client’s timeout does not cancel the task.
CREATION_ID="5b0214ae-9e39-460a-820a-f6ae3e24400b" # the id from the 202 response curl --fail-with-body --max-time 20 \ "https://api.rendergrid.io/ api/ public/ v1/ creations/ $CREATION_ID" \ -H "Authorization: Bearer $RENDERGRID_API_KEY"
import os import time import requests API = "https://api.rendergrid.io/ api/ public/ v1" key = os.environ["RENDERGRID_API_KEY"] creation_id = "5b0214ae-9e39-460a-820a-f6ae3e24400b" # the id from the 202 response # the 180 seconds are a setting of this example, not how long the model takes deadline = time.monotonic() + 180 while time.monotonic() < deadline: r = requests.get( f"{API}/creations/{creation_id}", headers={"Authorization": f"Bearer {key}"}, timeout=(5, 20), ) r.raise_for_status() creation = r.json() if creation["status"] in ("completed", "failed"): break time.sleep(5) # never poll more often than once every 5 seconds else: raise TimeoutError(f"Not done yet, keep the id: {creation_id}") if creation["status"] == "completed": print(creation["result_urls"]) else: print(creation["error"], creation["failure"])
// Node.js 22+, .mjs file const API = "https://api.rendergrid.io/ api/ public/ v1"; const headers = { Authorization: `Bearer ${process.env.RENDERGRID_API_KEY}` }; const creationId = "5b0214ae-9e39-460a-820a-f6ae3e24400b"; // the id from the 202 response const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // the 180 seconds are a setting of this example, not how long the model takes const deadline = Date.now() + 180_000; let creation; while (Date.now() < deadline) { const res = await fetch(`${API}/creations/${creationId}`, { headers, signal: AbortSignal.timeout(20_000), }); if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`); creation = await res.json(); if (["completed", "failed"].includes(creation.status)) break; await sleep(5000); // never poll more often than once every 5 seconds } if (creation?.status === "completed") { console.log(creation.result_urls); } else if (creation?.status === "failed") { console.log(creation.error, creation.failure); } else { console.log(`Not done yet, keep the id: ${creationId}`); }
The links in result_urls stay valid for one day, and then the file is deleted. Save the image to your own storage as soon as the status is completed.
Instead of polling, pass webhook_url in the request, and we send an event when the task is done. Keep polling as a fallback: a notification can be delayed or not arrive. The webhooks and idempotency guide covers signatures and retries.
If a task becomes failed, the charge returns to your balance by itself. For a new attempt, send a new request with a new X-Idempotency-Key: it is a new paid operation, and the old key does not restart the failed task. See how refunds work.
Which resolution should you choose: 1K, 2K, or 4K?
Nano Banana 2.1 makes images at 1K, 2K, and 4K. Each is its own request with its own price: $0.02 at 1K, $0.03 at 2K, and $0.04 at 4K. If you leave resolution out, the request is made and charged at 2K, the default for this model, even though the catalog’s root price is the 1K price. Set it in every request.
A tier is a size level, not a promise of an exact pixel count; width and height are not accepted. The three 1:1 images below are 1,024 by 1,024 pixels, 2,048 by 2,048 pixels, and 4,096 by 4,096 pixels.
One prompt, three resolutions
A closed linen-covered notebook, a wooden pencil and a white ceramic cup sit on a pale desk. View them from slightly above, keeping all three within a central arrangement and leaving even margins. Soft window light from the left reveals the cloth weave, wood grain and glazed ceramic. No lettering, logos, people, or watermarks.
Nano Banana 2.1
nano-banana-2.1 · 1K · 1:1 · $0.02
Nano Banana 2.1, 1K, 1:1, one attempt. The notebook, pencil, and cup sit near the middle of the image, seen from a high angle, steeper than the slight angle from above the prompt asked for: the desk top fills most of the frame. The margins are narrower at the sides than at the top and bottom, a small departure from the prompt’s even margins. The notebook is tilted. The pencil lies to its right with no eraser or metal band, and the cup is a small white tumbler without a handle. The linen weave and the wood grain of the desk are visible, and the cup’s shadow falls to the right, which fits light from the left; a bright, blurred window edge shows at the top left. The file is 1,024 by 1,024 pixels. There is no lettering.
Nano Banana 2.1
nano-banana-2.1 · 2K · 1:1 · $0.03
Nano Banana 2.1, 2K, 1:1, one attempt. The pencil lies along the notebook’s left edge here, not on its right as at 1K, and it has a metal band and an eraser. The cup is again a tumbler without a handle, with a patchy pale pattern on its side that looks like a reflection. The notebook cover shows brown flecks in the linen. The group sits near the middle, seen from a high angle, steeper than the slight angle from above the prompt asked for, with the desk top filling most of the frame. The margins are narrower at the sides than at the top and bottom, a small departure from the prompt’s even margins. A bright, blurred window shows at the top left. The file is 2,048 by 2,048 pixels. There is no lettering.
Nano Banana 2.1
nano-banana-2.1 · 4K · 1:1 · $0.04
Nano Banana 2.1, 4K, 1:1, one attempt. This is a different composition from the 1K and 2K images: the cup is a mug with a handle and a speckled glaze, and the pencil, with a gold-colored band and a pink eraser, lies to the right of the notebook. The linen weave, the wood grain of the desk, and faint ridges inside the mug are visible. A short dark mark on the pencil barrel looks like printing, but it is too small to read at the size shown, and the prompt asked for no lettering. The group sits near the middle, seen from a high angle, steeper than the slight angle from above the prompt asked for, with the desk top filling most of the frame. The margins are narrower at the sides than at the top and bottom, a small departure from the prompt’s even margins. The file is 4,096 by 4,096 pixels.
What the three images show
Each is its own request, one attempt from the same prompt, so they are not one image resized. The pencil lies right of the notebook at 1K, left of it at 2K, and right of it again at 4K, and has no eraser at 1K. The cup is a handleless tumbler at 1K and 2K and a mug with a handle at 4K.
In all three, the group sits near the middle in soft light, seen from a high angle, steeper than the slight angle from above the prompt asked for: the desk top fills most of each frame. The margins are narrower at the sides than at the top and bottom, a small departure from the prompt’s even margins.
The 4K image shows the linen weave, the wood grain, and faint ridges inside the mug. It also shows a short dark mark on the pencil that looks like printing but is too small to read, although the prompt asked for no lettering.
The tier is a request field, and each tier is its own request: here the same prompt gave a different composition at each tier.
How do you choose an aspect ratio?
aspect_ratio is an exact value such as 16:9, with no spaces. If you leave it out, the image is 1:1; a missing field does not mean auto.
Nano Banana 2.1 accepts 1:1, 16:9, 9:16, 4:3, 3:4, 2:3, 3:2, 5:4, 4:5, and 21:9, plus the extra tall and wide shapes 1:4, 1:8, 4:1, and 8:1, and auto, at every resolution. With auto, the model picks the shape. With reference images the ratio usually follows the first one; without them the shape is not guaranteed, so set aspect_ratio yourself when your layout depends on it.
Choose the ratio of the place the image will go, for example 16:9 for a wide banner or 9:16 for a tall one. A ratio or resolution the model does not support gets a 400 response before any charge, with the allowed values in error.details.supported.
Where does this guide not fit?
- Three images are one example. They show what one prompt gave on one run, one attempt each, and say nothing about how long a request takes.
- The five minutes are not a generation time. They run from a key and a balance to your first image; the USDT top-up before them has its own payment window.
- One image per request. For more, send several requests with different idempotency keys, within your account’s limits. See the 429 guide.
- Other models and features. Nano Banana Pro takes the same request with
modelset tonano-banana-pro, without1:4,1:8,4:1, and8:1. Reference images are in what is new in Nano Banana 2.1 and the reference images docs.
A failed request is free
Try your own prompt on Nano Banana 2.1
Try a prompt of your own in the playground on the model page, then use it in the request from this guide.
Open the playgroundQuestions and answers
How do I make my first image with the Nano Banana 2.1 API?
POST request to /images/generate with model set to nano-banana-2.1 and a prompt. Poll GET /creations/{id} until the status is completed, then take the links from result_urls.How much does an image cost at each resolution?
Is a failed request charged?
X-Idempotency-Key.Sources
- Quickstart documentationKey, request, and status check.
- Documentation: create an imageRequest fields and checks before the charge.
- Documentation: tasks and statusesStatuses, polling, result files, and webhooks.
- Documentation: models and parametersResolutions, aspect ratios, and defaults.
- Documentation: keys and authenticationCreating, passing, and storing a key.
- Rendergrid pricingThe price per image for each model and resolution.
- The images in this articleThe prompt and settings are shown with the three images.





