gpt-image-2 Image Generation and Editing

OpenAI-compatible gpt-image-2 text-to-image + image-edit API: drop in by switching base_url, multi-region endpoints, unified billing with your QCode key

Updated 2026-10-16

Need an API key? Sign up →Endpoints & base URLs →

On This Page

QCode.cc exposes a gpt-image-2 service whose request and response formats are compatible with the OpenAI Images API (a few parameter behaviors differ — see Differences vs the official OpenAI API), covering two endpoints:

  • Text-to-image POST /v1/images/generations — JSON request, generate images from text alone
  • Image edit POST /v1/images/edits — multipart upload of 1–8 source images (optional mask), repaint / modify / composite per the prompt (launched May 2026)

gpt-image-2 is OpenAI's latest image model (released April 2026) and currently has the strongest in-image text rendering of any public model — it can reliably render English and Chinese characters inside generated images.

ℹ️ OpenAI released gpt-image-2.5 on 2026-09-08 (API model names gpt-image-2.5-flare / gpt-image-2.5-sunburst). This service accepts gpt-image-2.5, gpt-image-2.5-flare and gpt-image-2.5-sunburst as compatibility model names, so clients already configured for the new names work as-is. All of these names work, with identical billing; the xhigh / max quality tiers are treated as high, and 2.5-only capabilities such as 4K / arbitrary resolutions are not supported yet.

What QCode.cc adds:

  • Works with the OpenAI SDK — change base_url and you are done; request and response shapes match OpenAI (including the multipart edits endpoint); a few parameter behaviors differ, see the differences table at the end
  • Multi-region access: global smart routing (api) / Asia (Korea / Taiwan / Hong Kong) / North America & Europe (Los Angeles) — pick the entry closest to your network
  • Single API key: reuse your existing QCode.cc cr_ key — same quota account as Claude Code and Codex
  • Unified usage view: image calls and chat calls are merged in your dashboard, plus a dedicated self-service usage page
  • Shared quota across endpoints: generations and edits share the same per-key 100 images/day cap and 2-concurrency limit

Common use cases: poster generation, illustrations, product imagery, UI mockups, social-media assets, image editing (local inpainting / multi-image composition / background swap / high-fidelity restoration).


Quick start

Text-to-image (generations)

Three lines of Python for your first image:

from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,  # typically 20-80s per image, occasionally over 100s; set at least 180s
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

with open("output.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))

Image edit (edits)

Upload an existing image + prompt, optionally with a mask for local inpainting:

from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),          # optional: PNG alpha; transparent area = repaint region
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
)

with open("edited.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))

⚠️ Always set timeout ≥ 180 s explicitly: the OpenAI SDK default is too short. gpt-image-2 inference is significantly slower than legacy text-to-image (see Latency & timeout below).


Endpoints

The gpt-image-2 service (both generations and edits) is available on every QCode.cc entry. Just append /qcode-img/v1 to the base:

Your location Recommended base_url Protocol Notes
China https://api.qcode.cc/qcode-img/v1 HTTPS Recommended by default
HK / SEA https://asia.qcode.cc/qcode-img/v1 HTTPS Asia node (Korea / Taiwan / Hong Kong, nearest)
North America / Europe https://us.qcode.cc/qcode-img/v1 HTTPS Los Angeles node

All entries route to the same service and billing system — usage and quota are unified. No entry caps a single request at 100 seconds; the server waits up to 180 seconds per request.

qcode-img is the path prefix dedicated to image generation and editing, parallel to /api (Anthropic) and /openai/v1 (OpenAI chat).


API reference

Common request headers

Header Required Value
Authorization ✓ Bearer cr_xxxxxxxxxxxxxxxx (your QCode.cc API key)
Content-Type ✓ application/json (generations)
multipart/form-data (edits)

Generations endpoint /v1/images/generations

Endpoint: POST {base_url}/images/generations Content-Type: application/json

Request body:

{
  "model": "gpt-image-2",
  "prompt": "A small ceramic vase with sunflower, photorealistic",
  "size": "1024x1024",
  "quality": "low",
  "n": 1
}

Fields:

Field Type Required Default Values
model string ✗ gpt-image-2 gpt-image-2 (also accepts gpt-image-2-low / -medium / -high, equivalent to setting quality; and the compatibility names gpt-image-2.5 / gpt-image-2.5-flare / gpt-image-2.5-sunburst, all usable with identical billing); any other model name returns 400 unsupported_model
prompt string ✓ — Image description, multilingual (incl. English & Chinese)
size string ✗ 1024x1024 auto / 1024x1024 / 1024x1536 / 1536x1024 / 2048x2048; invalid values return 422. The output size usually matches the requested size; in some cases the returned size differs (e.g. 1254×1254) — go by the actual size of the returned image
quality string ✗ medium low / medium / high (xhigh / max are treated as high); it does not affect the price (see Billing)
n integer ✗ 1 Images per call (1 – 4); > 4 returns 400 (no silent truncation)
background string ✗ auto auto / opaque; transparent returns 400 (the model cannot produce an alpha channel)
response_format string ✗ b64_json b64_json only; passing url returns 400
output_compression integer ✗ — 0 – 100, applies to JPEG / WebP; out-of-range values return 400
stream / partial_images — ✗ — Not supported yet; passing them returns 400

Edits endpoint /v1/images/edits

Endpoint: POST {base_url}/images/edits Content-Type: multipart/form-data (file uploads require form-data, not JSON)

Fields:

Field Type Required Default Values / notes
model string ✗ gpt-image-2 May be omitted; the edits endpoint always uses gpt-image-2
image file (× N) ✓ — Source image (PNG / JPEG / WebP); 1 – 8 images supported for multi-image composition (repeat the same field name: -F image=@a.png -F image=@b.png)
mask file ✗ — PNG alpha mask; transparent area = region to repaint; mask resolution must match image (scaled automatically); applies to single-image edits
prompt string ✓ — Edit instruction (multilingual)
size string ✗ auto auto / 1024x1024 / 1024x1536 / 1536x1024 / 2048x2048. The output size usually matches the requested size; in some cases the returned size differs (e.g. 1254×1254) — go by the actual size of the returned image. Invalid values return 422
quality string ✗ auto auto / low / medium / high (xhigh / max are treated as high); does not affect the price
n integer ✗ 1 Images per call (1 – 4); > 4 returns 400 (no silent truncation)
background string ✗ auto auto / opaque. transparent is not supported by gpt-image-2 (the model cannot produce an alpha channel; passing it returns 400)
output_format string ✗ png png / jpeg / webp
output_compression integer ✗ — 0 – 100, applies to JPEG / WebP (ignored for PNG); out-of-range values return 400
input_fidelity string ✗ — No need to pass it: the model always processes input images at high fidelity; passing low / high is ignored, any other value returns 400
response_format string ✗ b64_json Only b64_json is accepted (passing url returns 400)
user string ✗ — End-user identifier passed through (for abuse detection)

Upload size limits: single file ≤ 25 MB; total across files ≤ 50 MB (over the limit returns 413 image_too_large).

Response (same for both endpoints)

{
  "created": 1777135432,
  "data": [
    {
      "b64_json": "iVBORw0KGgo...(base64 PNG/JPEG/WebP, 1-3 MB)",
      "revised_prompt": "A small ceramic vase with sunflower..."
    }
  ]
}
  • b64_json: base64-encoded image data; render directly with <img src="data:image/<format>;base64,...">
  • revised_prompt: the model's improved version of your original prompt (optional to display)

Error responses

Errors follow the standard OpenAI schema:

{
  "error": {
    "type": "rate_limit_error",
    "code": "image_daily_limit",
    "message": "Daily image generation count limit reached..."
  }
}
HTTP code Meaning Billed
400 invalid_json / missing_prompt Request body is not valid JSON / prompt is missing No
400 unsupported_model Model name not supported (gpt-image-2 and its compatibility names gpt-image-2.5 / -flare / -sunburst are supported; gpt-image-1, dall-e-3 etc. return this error) No
400 stream_not_supported stream=true or partial_images was passed No
400 unsupported_background / unsupported_response_format / unsupported_n / unsupported_output_compression Parameter value not supported (see each endpoint's parameter table) No
400 invalid_multipart / invalid_content_type Malformed form on the edits endpoint (must be multipart/form-data) No
400 content_policy_violation and similar Content moderation rejected the request; change the prompt or the image No
401 invalid_api_key / key_disabled / key_expired API key invalid / disabled / expired No
413 image_too_large Single file > 25 MB, or total across files > 50 MB No
422 unsupported_size size value not supported (valid values are in each endpoint's parameter table) No
429 crs_daily_exhausted / crs_total_exhausted Your account's daily / lifetime budget is used up No
429 image_daily_limit Per-key daily 100-image cap reached (shared between generations and edits; raise on request) No
429 concurrency_exhausted Per-key concurrency cap of 2 reached (raise on request) No
501 endpoint_not_implemented The edits endpoint is temporarily closed for maintenance No
503 image_provider_unavailable The image service is temporarily unavailable; the response carries Retry-After — handle it per Timeout and retry No
503 service_overloaded / billing_backend_unavailable Service busy / billing backend temporarily unavailable, retry later No
504 upstream_timeout An edit request did not complete within 180 seconds No

Code examples

Text-to-image:

from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

img_bytes = base64.b64decode(result.data[0].b64_json)
with open("output.png", "wb") as f:
    f.write(img_bytes)
print("Saved output.png")

Image edit (single image + mask inpainting):

from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
    extra_body={"output_format": "png"},
)

img = base64.b64decode(result.data[0].b64_json)
with open("edited.png", "wb") as f:
    f.write(img)

Image edit (multi-image composition, 2 – 8 images):

result = client.images.edit(
    model="gpt-image-2",
    image=[
        open("scene.png", "rb"),       # 1st image: scene background
        open("product.png", "rb"),     # 2nd image: product to place
    ],
    prompt="Place the product naturally into the scene, match the lighting and shadows.",
    size="1536x1024",
    quality="high",
)

curl

Text-to-image:

curl https://api.qcode.cc/qcode-img/v1/images/generations \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "A cyberpunk Tokyo street at night",
    "size": "1024x1024",
    "quality": "low",
    "n": 1
  }' \
  | jq -r ".data[0].b64_json" | base64 -d > output.png

Image edit:

curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@cat.png" \
  -F "mask=@mask.png" \
  -F "prompt=put a tiny crown on the cat" \
  -F "size=1024x1024" \
  -F "quality=high" \
  -F "output_format=png" \
  | jq -r ".data[0].b64_json" | base64 -d > edited.png

Multi-image composition (just repeat -F image=@):

curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@scene.png" \
  -F "image=@product.png" \
  -F "prompt=Place the product naturally into the scene" \
  -F "size=1536x1024" \
  -F "quality=high"

JavaScript / Node.js / browser

Text-to-image:

const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/generations", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cr_YOUR_QCODE_API_KEY",
    "Content-Type":  "application/json",
  },
  body: JSON.stringify({
    model: "gpt-image-2",
    prompt: "A cyberpunk Tokyo street at night",
    size: "1024x1024",
    quality: "low",
    n: 1,
  }),
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;

Image edit (browser FormData):

const fd = new FormData();
fd.append("model", "gpt-image-2");
fd.append("image", imageFile);              // File object from <input type="file">
fd.append("mask", maskFile);                // optional
fd.append("prompt", "put a tiny crown on the cat");
fd.append("size", "1024x1024");
fd.append("quality", "high");
fd.append("output_format", "png");

const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/edits", {
  method: "POST",
  headers: { "Authorization": "Bearer cr_YOUR_QCODE_API_KEY" },
  // Don't set Content-Type manually — FormData sets multipart/form-data with the boundary
  body: fd,
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;

Quotas

Defaults

Dimension Default Notes
Daily image count 100 / day / key Resets at 00:00 Beijing time; shared between generations and edits
Concurrency 2 in flight Returns 429 concurrency_exhausted; shared across both endpoints
Upload size (edits only) 25 MB single file / 50 MB total Returns 413 image_too_large
Account budget Shared with your QCode.cc account dailyCostLimit / totalCostLimit Returns 429 crs_daily_exhausted

Defaults cover the vast majority of users. Contact support to raise.

Usage lookup

  • Dashboard — shows chat + image calls together (last activity, today's cost, lifetime cost, model distribution)
  • Self-service page: https://api.qcode.cc/qcode-img/usage — enter your API key to see the last 30 days of usage, detailed call list, ECharts trend (key is kept locally in your browser, never uploaded)

Billing

How billing works

generations and edits are billed the same way, per output image:

Billable item Unit price
Per output image $0.30
  • $0.30 per output image: generating n images costs n × $0.30
  • size / quality / the number of input images / mask / prompt length do not affect the price
  • gpt-image-2, gpt-image-2-low / -medium / -high, and the compatibility names gpt-image-2.5 / -flare / -sunburst all share the same price
  • As of 2026-10-07, the price is $0.30 per image (it was $0.15 per image from 2026-10-06; before that, billing was per-token)

Failures don't charge

Any failed request is never billed: 4xx (including content-moderation rejections) / 5xx, timeouts and client disconnects (closed connections) are not billed.

Currency

Costs are denominated in USD and settled per your QCode.cc account's currency policy (CNY / USD).


Latency & timeout settings

gpt-image-2 is an inference-based model and takes markedly longer than legacy text-to-image models. A single image usually takes 20–80 s, occasionally over 100 s, and in rare cases close to 180 s.

Practical advice:

  • The OpenAI Python SDK's default timeout is too short — always set timeout=180.0 or higher explicitly
  • Browser fetch has no default timeout; if you use AbortController, give it at least 180 s
  • If the request goes through your own reverse proxy / gateway, raise its read timeout to ≥ 180 s

Timeout and retry

  • 503 image_provider_unavailable: the image service is temporarily unavailable, and nothing is billed. Wait as instructed by the Retry-After response header (seconds), then retry with exponential backoff (30 s → 60 s → 120 s) for at most 3 attempts; if it keeps failing, contact support
  • 504 upstream_timeout / client-side timeout: a single generation exceeded 180 seconds. Retrying directly is fine; if it keeps timing out, simplify the prompt or reduce the number of input images
  • 429 crs_daily_exhausted / crs_total_exhausted: the account quota is used up, handled the same way as on the chat endpoints: a personal plan resets at 00:00 Beijing time (or buy a booster pack), a Pay-as-you-go Pack is renewed; see the error reference
  • 429 image_daily_limit / concurrency_exhausted: wait per the Retry-After header; if it keeps happening, contact support
  • Failed requests are not billed, so retrying never double-charges

Prompting tips

Text-to-image (generations)

  • Multilingual: Chinese, English, or mixed prompts all work
  • More detail is better: environment, composition, lighting, style, lens distance / focal length / angle
  • Avoid brand names / well-known people: the model may refuse or return blurry results (OpenAI content policy)
  • In-image text: gpt-image-2 is exceptional at rendering English / Chinese text inside images (poster titles, slogans, signage) — just put the literal text in the prompt, no special syntax
  • Content moderation: a prompt that violates the content policy returns 400 (e.g. content_policy_violation) and is not billed

Example:

A vintage poster in Bauhaus style, bold black text "MORNING COFFEE" centered,
warm orange and cream color palette, geometric shapes, slightly textured paper background

Image edit (edits)

  • Mask says "where", not "what": transparent area = region to repaint, opaque area is preserved. The prompt describes what to paint. Mask resolution must match image (system rescales).
  • For multi-image inputs, name each image's role in the prompt — e.g. "First image is the scene, second image is the product to place into it" — gpt-image-2 reads inputs in order.
  • No need to pass input_fidelity: gpt-image-2 always processes input images at high fidelity, automatically preserving faces / logos / text / product details (passing low / high is ignored, any other value returns 400).
  • Without a mask, the whole image is repainted per the prompt (the semantic structure is preserved, but every region may change).

Example:

# Local inpaint: add a crown, keep the rest unchanged
prompt = "Put a tiny golden crown on the cat's head. Keep everything else unchanged."
mask = (alpha PNG with only the head area transparent)

Differences vs the official OpenAI API

Dimension OpenAI official QCode.cc
SDK compatibility — ✅ Request / response formats are compatible, changing base_url is enough; the rows below list the behavioral differences
Billing Per token $0.30 per output image, n images = n × $0.30
/v1/images/generations (text-to-image) ✅ ✅
/v1/images/edits (image edit) ✅ ✅ Supports 1 – 8 image composition and mask inpainting
size — Output size usually matches size; sometimes it differs — go by the returned image
quality — Does not affect the price
background=transparent — ❌ Returns 400
response_format=url — ❌ b64_json only
stream + partial_images (incremental return) ✅ ⏳ Not supported yet, passing them returns 400
/v1/images/variations (pure variants) ✅ (DALL·E endpoint) ⏳ Not supported yet (approximate it with edits plus a descriptive prompt)
gpt-image-2.5 (flare / sunburst) ✅ (released 2026-09-08) ✅ Accepts the compatibility model names, all usable with identical billing; xhigh / max are treated as high, 2.5-only capabilities (4K etc.) are not supported yet

Online Playground

https://api.qcode.cc/qcode-img/ — try in your browser:

  • Both Text-to-image and Image-edit modes are wired up visually (upload, draw mask, pick background / output_format, etc.)
  • Enter your API key + prompt to generate immediately
  • English / Chinese UI toggle
  • Defaults to low quality
  • Includes full API reference inline (curl / Python / JavaScript tabs + parameter table + error codes)
  • One-click download as PNG / JPEG / WebP

FAQ

Q: What do I do about 503 image_provider_unavailable? A: The image service is temporarily unavailable and failed requests are not billed. Wait as instructed by the Retry-After header and retry (exponential backoff starting at 30 seconds, at most 3 attempts). If it keeps failing, contact support.

Q: Do you support gpt-image-2.5 (flare / sunburst)? A: You can use the model names gpt-image-2.5, gpt-image-2.5-flare and gpt-image-2.5-sunburst directly — all of these names work, with identical billing; the xhigh / max quality tiers are treated as high, and 2.5-only capabilities such as 4K are not supported yet.

Q: Why is the output size different from the size I sent? A: The output size usually matches the requested size; in some cases the returned size differs (e.g. 1254×1254), so go by the actual size of the returned image. If you need an exact size, crop or scale the image locally.

Q: Does quality affect the price? A: quality does not affect the price — whether low or high, it is $0.30 per output image.

Q: Are failed requests charged? A: No. 4xx / 5xx, timeouts, content-moderation rejections and client disconnects are not billed.


Get started with QCode

One API key for Claude Code, Codex and more — billed per token, per-model prices on qcode.cc/models

Enterprise →