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

Image generation with GPT Image 2, as an async job: submitting returns a job id at once (HTTP 202), then you poll the result or let a webhook push it. Text-to-image needs only a prompt; add a reference image for image-to-image. 1K / 2K / 4K tiers and any aspect ratio, billed per image, nothing charged on failure.

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
curl https://nezhagate.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-image-2", "prompt": "A cafe menu poster titled Autumn Specials listing three drinks with prices, clean layout", "size": "16:9", "resolution": "2K"}'

Response (HTTP 202)

JSON
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "queued",
  "created": 1791281400,
  "model": "gpt-image-2"
}

Step 2 · Poll every 2–3 seconds until status is succeeded or failed

curl
curl https://nezhagate.com/v1/images/jobs/img_7f3c9a1e2b4d6f8a0c1e3b5d \
  -H "Authorization: Bearer YOUR_API_KEY"

Response when it succeeds

JSON
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "succeeded",
  "created": 1791281400,
  "model": "gpt-image-2",
  "data": [
    {"url": "https://img.nezhagate.com/i/2be8cd16d37f3a4b9c0e1f2a3b4c5d6e.png"}
  ],
  "usage": {"images": 1, "resolution": "2K", "model": "gpt-image-2"}
}

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

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

Python
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": "gpt-image-2",
    "prompt": "A cafe menu poster titled Autumn Specials listing three drinks with prices, clean layout",
    "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("gpt-image-2.png", "wb") as f:
        f.write(requests.get(url).content)
    print("saved", url)
else:
    print("failed:", job["error"]["code"], job["error"]["message"])

Authentication

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

Create an API Key in the console to start.

Request parameters

The JSON body of POST /v1/images/generations:

ParameterTypeRequiredDescription
modelstringYesThe model id: gpt-image-2.
promptstringYesWhat to draw. For image-to-image, say what to change.
sizestringNoAspect ratio such as 16:9 (recommended), or a pixel size such as 1536x1024. Without it you get a 1:1 square.
resolutionstringNoTier: 1K (default), 2K or 4K.
qualitystringNoDetail level, at 1K only: low, medium (default) or high. 2K and 4K are always drawn at medium, and any other value counts as medium. It does not change the price; see Quality and native resolution below.
image / imagesstring / arrayNoReference images; sending any makes it image-to-image: one in image, several in images (up to 8). Each can be a public image URL, a data: URI or base64.
nintegerNoNumber of images. Best left out: for several images submit several jobs at once. With n, n images are held up front and the images actually delivered are billed.
callback_urlstringNoWhere to push the result when the job ends; see Webhooks below.

Other OpenAI parameters (background, output_format, response_format, style and the like) do not change the price and are not guaranteed to take effect; results are always PNG, returned as a url.

Price

Billed per image by 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
1K1$0.005
2K5$0.025
4K8$0.04

Aspect ratio, resolution and output size

Put the ratio in size and the tier in resolution. The image is delivered at exactly the size in the table: the tier sets the longest side and the other side follows the ratio. Ratios not in the table work the same way.

Aspect ratio1K2K4K
1:11024x10242048x20484096x4096
3:4768x10241536x20483072x4096
2:3683x10241365x20482731x4096
9:16576x10241152x20482304x4096
4:31024x7682048x15364096x3072
3:21024x6832048x13654096x2731
16:91024x5762048x11524096x2304
  • At 1K the model composes the picture at the closest landscape, portrait or square shape, and the gateway then centre-crops and resizes it to the size in the table; the further a ratio is from 3:2, 2:3 or 1:1, the more of the edges is cut. The gateway adds a sentence about the ratio (in English) to your prompt so the subject stays whole and centred; keep anything that must survive away from the edges.
  • The tiers that are drawn natively (see Quality and native resolution below) are drawn at your ratio, so nothing is cropped from the edges.
  • size can also be a pixel size (e.g. 1536x1024): the image is delivered at exactly that size (scaled down if the longest side is over 4096). The tier then comes from resolution, or without it from the longest side: up to 1536 is 1K, up to 2048 is 2K, larger is 4K. resolution can raise the tier but never lower it, and it does not change the delivered size, so do not pair a small size with a high tier.

Quality and native resolution

  • Without quality the image is drawn at OpenAI's medium detail level. At 1K you can choose low, medium or high, for text-to-image and image-to-image alike; 2K and 4K are always drawn at medium. Any other value (auto, xhigh, max and so on) counts as medium and never causes an error. The price depends only on the resolution tier, never on quality.
  • If quality holds 1K, 2K or 4K and resolution is not given, it is read as the resolution tier (size and price follow that tier).
  • 1K is drawn at the model's native frame of about 1.57 megapixels (1254×1254 for a square), and the gateway resizes it to the size in the table above.
  • 2K and 4K are drawn natively at the ratio you ask for, up to 3840 px on a side and about 8.3 megapixels: 2K 1:1 comes back as 2048×2048, 4K 16:9 as 3840×2160 and 4K 1:1 as 2880×2880. Where the 4K size in the table is larger, the gateway scales the picture up to it (about 7% on each side for 16:9, more for squarer ratios); to receive the native pixels as they are, send a pixel size within those limits, such as 3840x2160.
  • Tiers that are drawn natively only run on their native lines: when those are busy the job waits in the queue, and if it still cannot be drawn it fails with a full refund — it is never replaced by an enlarged 1K image.
  • A 1K job is occasionally finished on a backup line, where quality may not take effect.

Image-to-image and reference images

  • Send image (one picture) or images (several, up to 8; any beyond 8 are not used) and the job runs image-to-image; say in the prompt what to change. POST /v1/images/edits takes the same parameters.
  • Both endpoints take a JSON body only, not a multipart file upload, so the OpenAI SDK's images.edit() cannot be used as is: pass links or base64 as in the example below.
  • 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 a 400 that says which one and why; 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.

Image-to-image with two references

curl
curl https://nezhagate.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-image-2", "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} reports these statuses; every field is described in Async jobs. Poll every 2–3 seconds, or use a webhook.

StatusMeaning
queuedWaiting in line. Carries queue_position (jobs ahead of yours) and eta_seconds (expected wait).
processingRendering.
succeededDone. The result is in data[0].url, the billing detail in usage.
failedFailed. The reason is in error; the credits held for the job are refunded in full.

One account runs up to 50 jobs 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 and image links for 15 days.

How long it takes

From submit to result, 1K usually takes 20–60 seconds; 2K and 4K are drawn natively and usually take 30–120 seconds. Image-to-image and several references take longer, and a job the gateway retries on another line can take a few minutes.

Real calls over the last 7 days: median 25 s, 90% done within 42 s.

Errors and refunds

An error at submit comes back at once as HTTP 4xx / 5xx: no job is created and nothing is charged. A failure after the job was accepted is reported by the job endpoint, and the hold is refunded in full. Every code is listed under Error codes.

Errors at submit

HTTPcodeCauseWhat to do
400missing_prompt/v1/images/generations has no prompt.Add a prompt.
400invalid_requestA reference image cannot be read (dead link, not an image, over 16MB...; message says which one and why), /v1/images/edits has no reference image, the body is not a JSON object, or n is not an integer.Fix what message says and submit again.
400model_not_foundThe model id is misspelled, model is missing, or the model cannot be used on this endpoint (a chat model on the image endpoint, for example).Use a model id from GET /v1/models or the API reference.
401invalid_api_keyThe key does not exist, was deleted or is disabled, or the account is disabled.Check the key on the API Keys page of the console.
402insufficient_quotaNot enough balance to hold this request. The gateway holds the highest possible cost of the request first, so a burst of concurrent calls can trigger it too.After a burst, wait a few seconds and retry; otherwise top up.
429rate_limit_exceededOver the requests-per-minute limit set on this key (counted over the last 60 seconds). No Retry-After header.Wait a few seconds and retry, or raise the key's limit in the console.
503model_maintenanceThe model is under maintenance and takes no requests; no other model answers in its place meanwhile.Retry when maintenance ends; see Status.
503service_unavailableA temporary failure on our side, such as storing a reference file; /v1/responses also answers 503, with Retry-After, when no line is available for a moment.Retry shortly.

Failed jobs (status failed)

codeWhen you see itWhat to do
moderation_blockedImage: the model provider's safety system refused the prompt or a reference image (the code may also be content_policy_violation).Rewrite the prompt or replace the reference; resubmitting it unchanged is usually refused again.
upstream_errorAny other failure: every line was tried, the job waited 15 minutes without starting, the upstream refused without a reason, and so on; message says which.Submitting again usually works.

Webhooks instead of polling

Add callback_url when you submit and the moment the job ends, success or failure, the gateway pushes exactly what the poll endpoint returns to that URL, signed and retried on failure. You can also set an account-wide address under Settings → Webhook in the console. 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": "gpt-image-2", "prompt": "A cafe menu poster titled Autumn Specials listing three drinks with prices, clean layout", "size": "1:1", "callback_url": "https://your-domain.com/webhook"}'