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
title: "gpt-image-2 Image Generation and Editing" description: "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"
gpt-image-2 Image Generation and Editing¶
QCode.cc exposes a fully OpenAI-compatible gpt-image-2 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.
What QCode.cc adds:
- Drop-in for the OpenAI SDK — only the
base_urlchanges; request and response shapes are 100% identical (including the multipart edits endpoint) - Multi-region access: HK / Japan / US / EU — pick the entry closest to your network
- Single API key: reuse your existing QCode.cc
cr_key — same quota account as Claude Code, Codex, and Gemini CLI - Unified usage view: image calls and chat calls are merged in your dashboard, plus a dedicated self-service usage page
- Shared quota across endpoints:
generationsandeditsshare 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, # 30–120 s per image; set ≥ 180 s
)
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",
extra_body={"input_fidelity": "high"}, # high fidelity preserves original details
)
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-2inference 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 required) | https://api.qcode.cc/qcode-img/v1 |
HTTPS | Behind global CDN; medium / high may hit 524 (see CDN 100 s hard limit) |
| HK / SEA | https://asia.qcode.cc/qcode-img/v1 |
HTTPS | Hong Kong PoP |
| Europe | https://eu.qcode.cc/qcode-img/v1 |
HTTPS | Frankfurt PoP |
| North America | https://us.qcode.cc/qcode-img/v1 |
HTTPS | Los Angeles PoP |
All entries route to the same billing system — usage and quota are unified. Full endpoint reference: Endpoints & API paths.
qcode-imgis the path prefix dedicated to image generation and editing, parallel to/api(Anthropic),/openai/v1(OpenAI chat), and/gemini(Gemini).
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 | ✓ | — | Must be gpt-image-2 |
prompt |
string | ✓ | — | Image description, multilingual (incl. English & Chinese) |
size |
string | ✗ | 1024x1024 |
1024x1024 (square) / 1024x1536 (portrait) / 1536x1024 (landscape) |
quality |
string | ✗ | medium |
low / medium / high |
n |
integer | ✗ | 1 | Images per call (1 – 4) |
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 | ✓ | — | Must be 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 (auto = follow input aspect) |
quality |
string | ✗ | auto |
auto / low / medium / high |
n |
integer | ✗ | 1 | Images per call (1 – 4) |
background |
string | ✗ | auto |
auto / opaque / transparent (transparent requires PNG / WebP output) |
output_format |
string | ✗ | png |
png / jpeg / webp |
output_compression |
integer | ✗ | — | 0 – 100, applies to JPEG / WebP (ignored for PNG) |
input_fidelity |
string | ✗ | low |
low / high; high preserves faces / logos / text / product details — use for portrait restoration or product-on-background swaps |
response_format |
string | ✗ | b64_json |
b64_json / url |
user |
string | ✗ | — | End-user identifier passed through (for upstream abuse detection) |
Upload size limits: single file ≤ 25 MB; total across files ≤ 200 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 |
|---|---|---|
| 401 | invalid_api_key |
API key invalid or disabled |
| 401 | key_expired |
API key expired |
| 413 | image_too_large |
Single file > 25 MB, or total across files > 200 MB |
| 422 | unsupported_size |
size not in the supported set |
| 429 | crs_daily_exhausted |
Daily account budget reached |
| 429 | crs_total_exhausted |
Lifetime account budget reached |
| 429 | image_daily_limit |
Per-key daily 100-image cap reached (shared between generations and edits; raise on request) |
| 429 | concurrency_exhausted |
Per-key 2-concurrency cap reached (raise on request) |
| 503 | service_overloaded |
Global service load is high — retry later |
| 503 | image_provider_unavailable |
Upstream temporarily unavailable — retry later |
Code examples¶
Python (OpenAI SDK, recommended)¶
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={
"input_fidelity": "high",
"background": "transparent",
"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",
extra_body={"input_fidelity": "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 "input_fidelity=high" \
-F "background=transparent" \
-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" \
-F "input_fidelity=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("input_fidelity", "high");
fd.append("background", "transparent");
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 / 200 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¶
Per-image pricing¶
generations and edits share the same pricing table:
| size | low | medium | high |
|---|---|---|---|
| 1024×1024 | $0.08 (floor) | $0.08 (floor) | $0.211 |
| 1024×1536 | $0.08 (floor) | $0.08 (floor) | $0.165 |
| 1536×1024 | $0.08 (floor) | $0.08 (floor) | $0.165 |
| 2048×2048 | $0.08 (floor) | $0.08 (floor) | $0.285 |
$0.08 minimum¶
- When actual cost is below $0.08 you pay $0.08 (
low/mediumtypically hit this floor) - When actual cost is ≥ $0.08 you pay the real amount (no markup)
Multiple outputs & multi-input edits¶
n > 1scales linearly on output count, e.g.n=2+1024×1024high = 2 × $0.211 = $0.422- For
editsmulti-input (image=[…N]): billing is per output (n), not per input maskdoes not affect billing
Failures don't charge¶
Any 4xx / 5xx error is not billed; client disconnects (closed connection) are not billed either.
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 is significantly slower than legacy text-to-image (DALL·E 3 / SDXL):
| quality | Typical | Complex-prompt extreme |
|---|---|---|
low |
20 – 35 s | ~50 s |
medium |
50 – 90 s | ~120 s |
high |
70 – 120 s | ~150 s |
Edits latency is comparable to generations. Multi-image input / higher resolution / input_fidelity=high push toward the long end.
Practical advice:
- The OpenAI Python SDK's default timeout is too short — always set
timeout=180.0or higher explicitly - Browser
fetchhas no default timeout, but if you useAbortControllergive it at least 180 s - For
medium/highfrom mainland China, preferasia.qcode.cc(direct, no CDN 100 s limit)
CDN 100 s hard limit (524 errors)¶
HTTPS requests to api.qcode.cc / asia.qcode.cc / eu.qcode.cc / us.qcode.cc go through the global CDN (CloudFlare). The CDN forcibly returns 524 for any request that waits longer than 100 s for the origin to respond.
| quality | Safe behind CDN 100 s? |
|---|---|
low |
✅ Safe (< 35 s) |
medium |
⚠️ Occasionally near the ceiling (close to 100 s) |
high |
❌ Frequent 524 |
Mitigations (recommended for medium / high):
- Use the
qcode-imgdirect entry:https://api.qcode.cc/qcode-img/v1(no CDN, no 100 s limit) - Or accept occasional 524 + client-side retry
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-2is exceptional at rendering English / Chinese text inside images (poster titles, slogans, signage) — just put the literal text in the prompt, no special syntax
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-2reads inputs in order. input_fidelity=highpreserves faces / logos / text / product details — use for portraits, brand assets, product-in-scene composites.lowfor sweeping style changes.- Without a mask, the whole image is repainted per the prompt (the semantic structure is preserved, but every region may change).
Example:
# Local inpaint with high fidelity: add a crown, keep the rest unchanged
prompt = "Put a tiny golden crown on the cat's head. Keep everything else unchanged."
input_fidelity = "high"
mask = (alpha PNG with only the head area transparent)
Differences vs the official OpenAI API¶
| Dimension | OpenAI official | QCode.cc |
|---|---|---|
| SDK compatibility | — | ✅ 100% compatible, only base_url changes |
| Pricing | Per-token | Per the table above, $0.08 / image floor |
/v1/images/generations (text-to-image) |
✅ | ✅ |
/v1/images/edits (image edit) |
✅ | ✅ Launched May 2026: 1–8 image composition, mask inpainting, input_fidelity high preservation, background transparent output |
stream + partial_images (incremental return) |
✅ | ⏳ Not yet supported (full result returned at once) |
/v1/images/variations (pure variants) |
✅ (legacy DALL·E endpoint) | ⏳ Not yet supported (use edits + high fidelity + empty prompt as a workaround) |
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 input_fidelity / background / output_format, etc.)
- Enter your API key + prompt to generate immediately
- English / Chinese UI toggle
- Defaults to
lowquality (avoids CDN 524) - Includes full API reference inline (curl / Python / JavaScript tabs + parameter table + error codes)
- One-click download as PNG / JPEG / WebP
Related docs¶
- Endpoints & API paths — full list of QCode.cc entries, protocol paths, curl smoke-test
- Billing — plans, quotas, cost rules