NezhaGateNezhaGate
POST https://nezhagate.com/v1/images/generations

Image generation (async, job-based) backed by Google Nano Banana 2.1, the October 2026 upgrade of Nano Banana 2. Text-to-image needs only a prompt; for an edit put the references in image or images (a URL, a data: URI or base64), or call /v1/images/edits. Submitting returns a job id at once (HTTP 202); poll GET /v1/images/jobs/{id} for the image. Ratios such as 1:1, 3:4, 2:3, 9:16, 4:3, 3:2 and 16:9 at 1K / 2K / 4K, and wide 4:1, 1:4, 8:1 and 1:8 frames render directly too. Billed per image; failed requests are not charged.

Try in Playground →

Quick start

Three steps: submit a job, poll it, take the image link. Replace YOUR_API_KEY with your key and the commands below run as they are.

Step 1 · Submit (returns a job id at once, HTTP 202)
curl https://nezhagate.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "nano-banana-2.1", "prompt": "An orange cat on a windowsill watching the rain, warm desk lamp, cinematic, shallow depth of field", "size": "16:9", "resolution": "2K"}'
Response (HTTP 202)
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "queued",
  "created": 1791281500,
  "model": "nano-banana-2.1"
}
Step 2 · Poll every 2-3 seconds until status is succeeded or failed
curl https://nezhagate.com/v1/images/jobs/img_7f3c9a1e2b4d6f8a0c1e3b5d \
  -H "Authorization: Bearer YOUR_API_KEY"
Response when it succeeds
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "succeeded",
  "created": 1791281500,
  "model": "nano-banana-2.1",
  "data": [
    {"url": "https://img.nezhagate.com/i/2be8cd16d37f3a4b9c0e1f2a3b4c5d6e.png"}
  ],
  "usage": {"images": 1, "resolution": "2K", "model": "nano-banana-2.1"}
}

Step 3 · data[0].url is the image (PNG). It is kept for 60 days; download it to your own storage to keep it longer.

Complete example (Python: submit, wait, save to disk)
import time
import requests

BASE = "https://nezhagate.com/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

# 1. submit
job = requests.post(f"{BASE}/images/generations", headers=HEADERS, json={
    "model": "nano-banana-2.1",
    "prompt": "An orange cat on a windowsill watching the rain, warm desk lamp, cinematic, shallow depth of field",
    "size": "16:9",
    "resolution": "2K",
}).json()
if "error" in job:
    raise SystemExit(job["error"]["message"])

# 2. poll every 3 seconds until it finishes
while job["status"] not in ("succeeded", "failed"):
    time.sleep(3)
    job = requests.get(f"{BASE}/images/jobs/{job['id']}", headers=HEADERS).json()

# 3. download the image
if job["status"] == "succeeded":
    url = job["data"][0]["url"]
    with open("nano-banana-2.1.png", "wb") as f:
        f.write(requests.get(url).content)
    print("saved", url)
else:
    print("failed:", job["error"]["message"])

Authentication

Header
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Create an API Key in the console to start.

Request body

ParameterTypeRequiredDescription
model string Yes Model ID, here nano-banana-2.1.
prompt string Yes Text prompt describing the image.
size string No Output aspect ratio. Recommended: pass a ratio — 1:1, 3:4, 2:3, 9:16, 4:3, 3:2, 16:9 — and the model renders natively at that ratio with no subject cropping. Pixel sizes (e.g. 1024x1024, 1024x1536, 1536x1024) are also accepted. Default 1:1 (square).
resolution string No Resolution tier: 1K (default) / 2K / 4K, billed by tier. Use it with a ratio in size, e.g. {"size": "16:9", "resolution": "2K"}; the exact pixels per tier are under "Aspect ratio, resolution and output size" below. When size is a pixel size (e.g. 2048x1152), the tier follows its longest side.
n integer No Always 1: each job returns one image. A larger value still returns one image and charges for one; for several images submit several jobs at once.
image string No Image-to-image: a reference image as a public URL, a data: URI, or raw base64. When present the request runs true identity-preserving image-to-image at the chosen size/ratio — equivalent to calling /v1/images/edits.
images array No Several reference images, up to 8 (only the first 8 are used if you send more): an array of strings or of {"image_url": "..."} objects; each a public image URL, a data: URI or base64, up to 16MB. Sending them runs image-to-image, the same as /v1/images/edits. For one reference the image field above also works.

Request example

cURL
# 1) submit -> 202 {"id":"img_...","status":"queued"}
curl https://nezhagate.com/v1/images/generations -H 'Authorization: Bearer YOUR_API_KEY' -H 'Content-Type: application/json' -d '{"model": "nano-banana-2.1", "prompt": "a serene ink-wash poster, lots of negative space", "size": "16:9", "resolution": "2K"}'
# 2) poll until status=succeeded
curl https://nezhagate.com/v1/images/jobs/img_3f9a...c2 -H 'Authorization: Bearer YOUR_API_KEY'

Response

200 · JSON
{
  "id": "img_3f9a...c2",
  "object": "image.generation.job",
  "status": "queued",
  "model": "nano-banana-2.1"
}

Price

Billed per image by resolution tier only: aspect ratio, text-to-image or image-to-image make no difference. The tier price is held when you submit and refunded in full if the job fails. 1 credit = $0.005.

TierCredits per imageUSD per image
1K3$0.015
2K5$0.025
4K8$0.04

Each job returns exactly one image: whatever n you send, you get one image and pay for one. For several images, submit several jobs at once (an account renders up to 50 at the same time).

Aspect ratio, resolution and output size

Put the ratio in size and the tier in resolution (1K by default, 2K or 4K). The model renders at the chosen ratio directly; it does not draw a square and crop it. The delivered image has a longest side of 1024 / 2048 / 4096 pixels and the other side follows the ratio. Common ratios:

Aspect ratio1K2K4K
1:11024x10242048x20484096x4096
3:4768x10241536x20483072x4096
2:3683x10241365x20482731x4096
9:16576x10241152x20482304x4096
4:31024x7682048x15364096x3072
3:21024x6832048x13654096x2731
16:91024x5762048x11524096x2304

Besides these seven, 4:5, 5:4, 21:9, 1:4, 4:1, 1:8 and 8:1 also render natively (same longest-side rule). Any other ratio is drawn at the closest landscape, portrait or square shape and then cropped to your ratio, which can cut off part of the picture.

size can also be a pixel size (e.g. 1536x1024): the image is delivered at exactly that size and the tier follows the longest side: up to 1536 is 1K, up to 2048 is 2K, larger is 4K. resolution accepts only 1K / 2K / 4K (any case); any other value is ignored and the tier comes from size, 1K by default. Without size you get a 1:1 square.

Image-to-image and reference images

  • Send image (one picture) or images (several, up to 8; only the first 8 are used if you send more) and the job runs image-to-image; say in the prompt what to change. POST /v1/images/edits takes the same parameters.
  • Each reference can be a public image URL (http or https), a data: URI or plain base64, up to 16MB each, in a common format such as JPEG, PNG or WebP.
  • A URL has to download the image itself: not a web page, and not behind a login or hotlink protection. A reference we cannot read is refused at submit with 400 and the reason; no job is created and nothing is charged.
  • The output ratio comes from size, not from the reference. To keep the original ratio, set size to it.
  • We host the references for you and keep them for 7 days.
curl · Image-to-image with two references
curl https://nezhagate.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "nano-banana-2.1", "prompt": "Keep the people, change the background to a beach at night with warm string lights", "images": ["https://example.com/people.jpg", "https://example.com/beach.jpg"], "size": "3:4", "resolution": "2K"}'

Job status and fields

GET /v1/images/jobs/{id} always returns id, object (image.generation.job), status, created (Unix seconds) and model; the other fields depend on the status:

statusMeaningExtra fields
queuedWaiting in the queuequeue_position (jobs ahead of yours), eta_seconds (estimated wait in seconds, a guide only)
processingRendering—
succeededDonedata[].url (the image link; our image host keeps it for 60 days); usage.images (images delivered), usage.resolution (billed tier)
failedFailed; the amount held at submit has been refunded in fullerror.message, error.type, error.code

Poll every 2-3 seconds. One account renders up to 50 images at a time; further jobs wait in submission order, and a job that has not started after 15 minutes fails and is refunded in full. Job records are kept for 3 days, after which the job id returns 404, but the image link stays valid for its 60 days. Only the account that submitted a job can read it.

How long it takes

Typical time from submit to result, as a guide. Image-to-image takes a few to a dozen seconds longer; a job the gateway re-runs on another line can take 1-2 minutes.

TierTypical time
1K25–40 s
2K25–50 s
4K35–80 s

Errors and refunds

Every error has the same shape, {"error": {"message", "type", "code", "param"}}; branch on code.

Errors returned at submit (no job is created and nothing is charged)

HTTPcodeCauseWhat to do
400missing_promptprompt is emptyAdd a prompt
400model_not_foundThe model id is wrong or not available right nowCheck the id; /v1/models lists the available ones
400invalid_requestA reference image cannot be read (dead link, not an image, over 16MB...); message says which one and whyUse a direct image link or send it as base64
401invalid_api_keyThe key is wrong, deleted or disabledCheck the key in the console
402insufficient_quotaNot enough balance to hold this jobTop up and retry
429rate_limit_exceededOver the per-minute limit set on this keySlow down, or raise the key limit in the console
503model_maintenanceThe model is under maintenanceRetry later; see the status page
503service_unavailableA temporary error on our side (e.g. storing your reference failed)Retry shortly

Failed jobs (the job was accepted and later ended with status failed; the hold is refunded in full)

SituationWhat you seeWhat to do
The prompt or a reference did not pass the Google safety reviewerror.message such as Content blockedRewrite the prompt or change the reference; resubmitting it unchanged is usually refused again
A rendering line failed or timed out (we retry on other lines first and only return a failure when all of them fail)error.code such as upstream_error or upstream_timeout, with the reason in messageSubmit again
The job waited 15 minutes without startingerror.message says soSubmit again later

Use a webhook instead of polling

For production, add callback_url when you submit. When the job ends, successfully or not, we POST the same JSON as the job endpoint to that URL as image.completed or image.failed, with signature headers you can verify. You can also set one URL for the whole account under Settings > Webhook. Webhook docs

curl · callback_url
curl https://nezhagate.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "nano-banana-2.1", "prompt": "An orange cat on a windowsill watching the rain, warm desk lamp, cinematic, shallow depth of field", "size": "1:1", "callback_url": "https://your-domain.com/webhook"}'