Generate and edit images with the GPT Image 2 API
The GPT Image 2 API on apiToken.sale is two routes — POST /v1/images/generations for new assets and POST /v1/images/edits for reference-based edits — behind the same Bearer key and prepaid balance as your GPT text calls. Usage bills per token at half the official OpenAI rates. This guide gives the exact requests, the SDK path, the real price table and the surface limits worth knowing before you ship.
·
The generation route in one request
GPT Image 2 is an image model you call over the OpenAI-compatible surface: send a prompt to /v1/images/generations with model gpt-image-2 and an Authorization: Bearer header, and you get back one PNG. No separate image plan, no second key — the same sk-pool credential and prepaid balance that cover GPT, Claude and Gemini calls settle image usage too.
curl https://router.apitoken.sale/v1/images/generations \
-H "Authorization: Bearer $APITOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A precise technical cutaway of a lunar rover",
"quality": "low"
}'Official GPT Image fields are accepted and converted onto this pool. Extra keys (user, stream, moderation, style) are ignored, not 400. quality medium/high/auto still generate at the pool's low tier. output_format jpeg or webp transcodes the native PNG locally; omit or png keeps PNG. response_format=url is ignored — the body is always b64_json. n may be 1–10; each extra image is another native turn on the same home. background=auto is opaque; transparent prepends a cutout sentence and asks for a real PNG alpha channel — inspect the file; a missing alpha is still HTTP 200, not 502. size selects a proportion, not a pixel lock. 2048x2048 and 3840x2160 map to 1:1 and 16:9; the PNG stays around 1.57 megapixels and the response size field is the real IHDR.
| size | Proportion | Steer target (inspect the PNG) |
|---|---|---|
| omitted or auto | no size steer | typically ~1254×1254; not a lock |
| 1024x1024, 1:1, 2048x2048 | 1:1 | 1254×1254 |
| 1536x1024 or 3:2 | 3:2 landscape | 1536×1024 |
| 1024x1536 or 2:3 | 2:3 portrait | 1024×1536 |
| 4:3 | 4:3 | 1448×1086 |
| 16:9, 2048x1152, 3840x2160 | 16:9 | 1672×941 |
| 9:16, 2160x3840 | 9:16 | 944×1665 |
1024x1024 is the square bucket, not a 1024-pixel lock. 1536x1024 and 1024x1536 are the 3:2 and 2:3 cuts of the same megapixel budget. The table is the prompt-steer target. If the PNG header does not match the bucket, the API still returns HTTP 200 and the PNG — put IHDR and alpha checks in your acceptance gate, not in an assumption that the route will 502.
POST /v1/images/* is non-streaming. n=2..10 runs sequential native turns and returns data[] of that length. For streamed preview frames, use the separate Responses image_generation tool with partial_images (below) — trivial prompts may skip partials.
See also: GPT Image 2 API cost and 50% B2C savings
Edit existing images with up to five PNG, JPEG or WebP references
Edits go to a different route and a different content type. POST multipart/form-data to /v1/images/edits with the same gpt-image-2 model, your prompt, and between one and five PNG, JPEG or WebP reference images (each file ≤50 MB). The references are how you ask for a targeted change — restyle this product shot, swap this background, extend this banner — instead of regenerating from scratch.
curl https://router.apitoken.sale/v1/images/edits \ -H "Authorization: Bearer $APITOKEN_API_KEY" \ -F "model=gpt-image-2" \ -F "prompt=Replace the backdrop with a seamless light-gray studio sweep" \ -F "image=@packshot.png" \ -F "image=@brand-swatch.png"
- Repeat the field name image for each file, or send image[]. Multipart mask is ignored on this route — use Responses input_image_mask for inpaint.
- References are PNG, JPEG or WebP, each at most 50 MB. GIF, HEIC and other types are rejected.
- The cap is five references per call — pick the few that carry the instruction rather than dumping the whole asset library.
- Every reference is billed as image input, so edits cost more than a pure-prompt generation of the same output.
- The response shape matches generation: b64_json plus actual size/background/output_format. jpeg/webp on this route are local transcodes of the native PNG.
Deeper editing workflows: masks, batches and acceptance checks →
Region inpaint and Responses image_generation
A multipart mask on /v1/images/edits is ignored so the SDK still gets an edit of the whole image. Native Codex ignores that field. To change only part of a picture — or to run the hosted image_generation tool from a GPT text model — call POST /v1/responses (Chat Completions maps the same hosted tools onto Responses). Put the source PNG in input as input_image when editing, and add tools: [{type:"image_generation", …}]. For a mask, set input_image_mask.image_url to a PNG data URL. Transparent pixels in the mask are the region to edit; opaque pixels stay. The mask must be the same size as the source. file_id masks are not supported — there is no Files API on this plane — so official OpenAI samples that upload a mask with files.create will not run here.
import base64, os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
api_key=os.environ["APITOKEN_API_KEY"],
base_url="https://router.apitoken.sale/v1",
)
def png_url(path):
return "data:image/png;base64," + base64.b64encode(Path(path).read_bytes()).decode()
response = client.responses.create(
model="gpt-5.6-sol",
input=[{
"role": "user",
"content": [
{"type": "input_text", "text": "Change only the masked region."},
{"type": "input_image", "image_url": png_url("photo.png")},
],
}],
tools=[{
"type": "image_generation",
"output_format": "webp",
"partial_images": 2,
"input_image_mask": {"image_url": png_url("mask.png")},
}],
)- Use a text GPT model on /v1/responses or /v1/chat/completions (for example gpt-5.6-sol), not gpt-image-2 — that id belongs to the Images routes.
- Both the source and the mask must be data:image/png;base64,… URLs, not https:// and not OpenAI file ids.
- Responses image_generation forwards output_format jpeg or webp (real file magic) and partial_images 1..=3; SSE emits response.image_generation_call.partial_image when partials arrive.
- background=transparent is rewritten to opaque and input_fidelity is dropped — those fields 400 on this ChatGPT image tool (gpt-image-2-codex). Quality/size on the tool still remap; the completed item echoes what ChatGPT returned.
- The mask is not billed as a second reference image; settlement still follows image-input and image-output tokens on the turn.
- POST /v1/images/* can return jpeg/webp by transcoding the native PNG. Real jpeg magic and partial_images SSE remain on Responses image_generation. Do not mix the two contracts.
Call it from the official OpenAI SDK
You can keep the official OpenAI SDK. Set base_url and api_key as for text models. Extra keys such as user, stream and moderation are ignored. response_format=url still returns b64_json. size=2048x2048 is accepted and converted to the square aspect; the PNG is not 2K pixels — read the response size field. The sample below is a typical SDK call.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["APITOKEN_API_KEY"],
base_url="https://router.apitoken.sale/v1",
)
result = client.images.generate(
model="gpt-image-2",
prompt="A clean isometric diagram of a wind turbine",
quality="low",
size="3:2",
)
png_bytes = result.data[0].b64_json # decode base64 and write to diskFor edits, the same client exposes images.edits with the reference files opened in binary mode. Keep the key in a server-side environment variable; image endpoints are exactly as sensitive as chat ones because they draw from the same balance.
What a generation actually costs
There is no honest fixed price per picture. GPT Image 2 bills per token across four usage legs — text input (your prompt), image input (references on edits), cached input and image output — and the request total follows the terminal usage the API reports, not the PNG's byte size or dimensions.
| Usage leg | Official per 1M tokens | Price here |
|---|---|---|
| Fresh text input | $5 | $2.50 |
| Fresh image input | $8 | $4 |
| Cached text input | $1.25 | $0.625 |
| Cached image input | $2 | $1 |
| Image output | $30 | $15 |
- Every leg gets the flat 50% B2C discount; cached text and image input bill at 25% of the normal input rate before the discount applies.
- Read the usage object on each response and log it next to the asset — it is the billing authority, and it is what the dashboard charge reconciles against.
- gpt-image-2 is an alias of the immutable gpt-image-2-2026-04-21 snapshot, so behavior does not drift between calls; pin the dated ID if you want that guarantee spelled out in code.
Resist quoting a per-image price on your own pricing page from a handful of test renders. Output usage varies with the asset, and a number derived from three samples will be wrong in production. Sum the legs from real usage over a week, then decide.
Limits of the current image surface
Plan around what the Codex pool can actually emit. Official client fields are converted onto that envelope:
- POST /v1/images/* is non-streaming. n=1..10 runs that many sequential native turns and bills them all. n>10 is capped at 10.
- Extra JSON keys are ignored. openai/gpt-image-2 is admitted as gpt-image-2. GET /v1/models lists the two ids and the image routes.
- size is a proportion: 2K/4K strings map to 1:1 or 16:9, and the PNG stays ~1.57 megapixels. quality medium/high still generate at low. jpeg/webp are local transcodes. background=transparent is a cutout prompt.
- The 200 body includes actual size, background, output_format and usage. Missing usage after a PNG is the only post-success 502 on this route.
- Edits accept one to five PNG, JPEG or WebP references (each ≤50 MB). image[] matches image. mask is ignored — region inpaint is the Responses image_generation path above.
- Image usage settles against the same prepaid balance as GPT, Claude and Gemini calls — one pool to watch, not four.
If you need a different image model for comparison, the Gemini-side image route is documented alongside this one, and the head-to-head guide covers where each wins.
Keep image spend contained on a shared balance
Because image output is the expensive leg and batch loops multiply it, give the image worker its own API key with a lifetime spending limit. A runaway render job then stops at its own ceiling instead of draining the balance your chat traffic depends on, and per-key usage in the dashboard tells you exactly which worker spent what.
- 01Create a dedicated key in the dashboard for the image pipeline and set its lifetime spending limit to the batch budget.
- 02Send one bounded generation request (the curl above) and confirm the returned PNG plus a usage object with the expected legs.
- 03Run your real prompt set in a small loop, record terminal usage per asset and reconcile the total against the dashboard charge.
- 04Only then scale to full batch volume, keeping the key's limit aligned with the budget you actually approved.
Frequently asked questions
What endpoint does the GPT Image 2 API use?
POST /v1/images/generations for a new image and POST /v1/images/edits for reference-based edits, both on the OpenAI-compatible base URL https://router.apitoken.sale/v1 with an Authorization: Bearer header.
Can GPT Image 2 edit an existing image?
Yes. The edits route accepts multipart/form-data with one to five PNG, JPEG or WebP files (each ≤50 MB) plus a prompt. Repeat the field name image, or send image[]. Multipart mask is ignored; use Responses input_image_mask to inpaint a region.
How do I inpaint only part of an image?
Call POST /v1/responses with a GPT text model, the source PNG as input_image, and tools: [{type:"image_generation", input_image_mask:{image_url:"data:image/png;base64,…"}}]. You can also set output_format jpeg|webp and partial_images 1..=3. Transparent mask pixels are the region to change. Do not send mask to /v1/images/edits, and do not use file_id. Chat Completions maps the same image_generation tool onto Responses.
What is the exact model ID for GPT Image 2?
Use gpt-image-2, which aliases the immutable gpt-image-2-2026-04-21 snapshot. Pin the dated ID in code if you want the snapshot spelled out explicitly.
How much does GPT Image 2 cost per image?
There is no fixed per-image price: billing follows terminal usage across text input ($5/M official), image input ($8/M), cached input (25% of fresh) and image output ($30/M), with a flat 50% discount on every leg here — $2.50, $4 and $15 per 1M respectively.
Does GPT Image 2 support transparent backgrounds or streaming?
On POST /v1/images/*: send background=transparent for a cutout PNG with a real alpha channel; omit, opaque or auto for solid; missing alpha is still HTTP 200. stream is ignored. On Responses image_generation: background=transparent is rewritten to opaque; use partial_images 1..=3 for SSE response.image_generation_call.partial_image instead.
Can I set the image size?
You set a proportion, not 2K/4K pixels. omitted or auto typically lands near 1254×1254. 1024x1024, 1:1 and 2048x2048 steer square; 3840x2160 steers 16:9. The response size field is the PNG IHDR, not the request. If the header differs, the API still returns HTTP 200.
Does image generation need a separate key or balance?
No. It uses the same Bearer key and prepaid balance as all other supported models — GPT, Claude and Gemini included — though a dedicated key with a lifetime spending limit is sensible for batch image workers.
Create an account with Google or GitHub and test the gateway with $5 of platform bonus credit.