gpt-image-2-official
GPT Image 2 stable channel — full feature surface with quality tiers, batches up to 4, mask inpainting, and background control.
The stable channel of GPT Image 2 on reAPI — async
/api/v1/images/generations with the full feature surface: quality tiers
(auto / low / medium / high), batches up to 4 images,
mask-based inpainting, and background control. The channel always
returns PNG. See current pricing on the
model page.
Wire id is gpt-image-2-official. The doc / pricing page /
playground all label this variant as "Stable" for clarity, but the
request body must set "model": "gpt-image-2-official". The shorter
gpt-image-2 is a separate variant — see
Differences from gpt-image-2.
Quick example
curl https://reapi.ai/api/v1/images/generations \
-H "Authorization: Bearer rk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2-official",
"prompt": "ancient castle beneath a starry sky",
"size": "16:9",
"resolution": "2k",
"quality": "high",
"n": 1
}'import requests
resp = requests.post(
"https://reapi.ai/api/v1/images/generations",
headers={
"Authorization": "Bearer rk_live_xxx",
"Content-Type": "application/json",
},
json={
"model": "gpt-image-2-official",
"prompt": "ancient castle beneath a starry sky",
"size": "16:9",
"resolution": "2k",
"quality": "high",
"n": 1,
},
timeout=30,
)
print(resp.json())const r = await fetch("https://reapi.ai/api/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer rk_live_xxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2-official",
prompt: "ancient castle beneath a starry sky",
size: "16:9",
resolution: "2k",
quality: "high",
n: 1,
}),
});
console.log(await r.json());package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"model": "gpt-image-2-official",
"prompt": "ancient castle beneath a starry sky",
"size": "16:9",
"resolution": "2k",
"quality": "high",
"n": 1,
})
req, _ := http.NewRequest("POST",
"https://reapi.ai/api/v1/images/generations", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer rk_live_xxx")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
}Submit response
{
"id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
"model": "gpt-image-2-official",
"status": "processing",
"created_at": 1735000000
}Poll GET /api/v1/tasks/{id} (see the Tasks reference) until
status === "completed". The completed payload's output.image_urls
holds the generated image URLs (length = n), valid for 7 days.
Authentication
Every call needs a Bearer token. Generate keys at reapi.ai/settings/apikeys.
Authorization: Bearer YOUR_API_KEYKeys carry the active workspace's billing scope — there is no separate project header.
Endpoint
POST /api/v1/images/generations
GET /api/v1/tasks/{id}Submission is async. The POST returns immediately with a task_id; the
task endpoint returns the same envelope until completion. Polling does
not consume credits.
Request body
model — required
string. Must be "gpt-image-2-official".
prompt — required
string, 1–4,000 characters. English and Chinese both supported.
Detailed prompts produce better results. Every prompt goes through
pre-submission moderation; rejected prompts return 400 at no charge.
Don't restate the ratio in the prompt — pass it via size.
Repeating it confuses the upstream.
Failure modes.
- Missing / empty →
400 prompt is required(code20002). - Longer than 4,000 chars →
400 prompt must be at most 4000 characters(code20007).
size — string, default "1:1"
Output ratio. One of these 14 values (or auto to let the upstream
pick from the prompt / first reference image):
auto
1:1 16:9 9:16 4:3 3:4
3:2 2:3 5:4 4:5
2:1 1:2 21:9 9:21This channel additionally accepts a pixel string WIDTHxHEIGHT (e.g.
1024x1024, 3840x2160); the upstream snaps it to the closest
supported dimension. Anything outside the list and not a pixel string
is rejected with 400.
When size is omitted:
- T2I (no
image_urls) → defaults to"1:1". - I2I (
image_urlsset) → output mirrors the first reference image's ratio (upstream-side derivation; gateway omits the field).
4K constraint
resolution: "4k" is only valid with the six widescreen sizes below.
Other ratios — including auto — exceed the model's total-pixel cap
and are rejected with 400. size is required when
resolution: "4k"; sending 4K with no size is rejected before the
request leaves the gateway.
size | 1k | 2k | 4k |
|---|---|---|---|
1:1 | 1024×1024 | 2048×2048 | ❌ |
3:2 / 2:3 | 1536×1024 | 2048×1360 | ❌ |
4:3 / 3:4 | 1024×768 | 2048×1536 | ❌ |
5:4 / 4:5 | 1280×1024 | 2560×2048 | ❌ |
16:9 / 9:16 | 1536×864 | 2048×1152 | 3840×2160 |
2:1 / 1:2 | 2048×1024 | 2688×1344 | 3840×1920 |
21:9 / 9:21 | 2016×864 | 2688×1152 | 3840×1648 |
auto | server picks | server picks | ❌ |
3:2 / 2:3 at 2K resolves to 2048×1360 — 1360 is the nearest
16-aligned approximation of 3:2 (under 0.5% off). Other cells are
exact.
4K is widescreen-only. resolution: "4k" requires size to be
one of 16:9, 9:16, 2:1, 1:2, 21:9, or 9:21. Sending 4K
with auto, a non-widescreen ratio, or no size returns 400 4K requires an explicit size in {16:9, 9:16, 2:1, 1:2, 21:9, 9:21}
(code 20003). See the 4K table under size above for the full grid.
resolution — string, default "1k"
1k / 2k / 4k. Case-insensitive — "2K" and "2k" are
equivalent. Drives pricing.
quality — string, default "auto"
auto / low / medium / high. Higher tiers are slower and price
separately.
auto bills at the high rate. The upstream does not honor a
lower-tier hint when auto is set — the request runs at high
internally. reAPI mirrors that on billing: auto (and any request
that omits quality) is charged at the high rate. To pay the
low or medium rate, set quality explicitly.
n — integer, default 1
Number of images per request. Range 1–4. Each generated image is
billed individually — a 4-image batch costs 4× the per-image
rate. output.image_urls length matches n.
image_urls — string[]
Reference images for image-to-image. Up to 16 entries. Triggers I2I when set. Public HTTP(S) URLs only.
No data: URIs. reAPI rejects base64 inputs platform-wide. Upload
to your own object storage (S3 / R2 / OSS) and pass the URL.
mask_url — string
PNG mask URL for inpainting. Requires image_urls with at least
one entry. The mask must:
- carry an alpha channel where the model should paint, and
- share dimensions with the first entry in
image_urls.
Public HTTP(S) URL only. Mismatched dimensions or a fully opaque mask
return 400 from upstream.
background — string, default "auto"
auto / opaque / transparent.
transparent is silently downgraded. gpt-image-2-official does
not produce transparent output even when explicitly requested.
Pre- or post-process client-side if you need transparency.
moderation — string, default "auto"
auto / low. low is more lenient — useful when prompts that
should pass are getting rejected.
Response envelope
Submit and poll share the same shape — only status and output
fill in over time.
{
"id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
"model": "gpt-image-2-official",
"status": "completed",
"created_at": 1735000000,
"output": {
"image_urls": [
"https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png",
"https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/1.png"
]
},
"error": null
}| Field | Type | Notes |
|---|---|---|
id | string | Task identifier — keep it for polling and audit |
model | string | Echo of the submitted model |
status | string | processing / completed / failed |
created_at | integer | Submission unix timestamp |
output | object | null | null until completion |
output.image_urls | string[] | Generated image URLs — length = n, valid for 7 days |
error | object | null | Populated on failed — { code, message } |
Upstream errors (502 / 503)
reAPI does not surface raw upstream 5xx codes to the caller. When
the upstream provider returns 502 Bad Gateway, 503 Service Unavailable, or a connection failure, the worker retries up to 5
attempts with exponential backoff (~30s total budget). If all retries
fail, the task ends with one of these reAPI-specific codes (returned
via GET /api/v1/tasks/{id} as error.code):
| reAPI code | Meaning | Origin |
|---|---|---|
80001 | provider_submit_failed | Upstream 5xx / network on submit |
80002 | provider_polling_timeout | Wall-clock cap reached while polling |
80003 | provider_failed | Upstream returned a terminal failure |
See Errors catalog for the full code list.
Validation errors
All cases below return HTTP 400 with the noted code. Pattern-match on
code, not message — message strings carry request-specific context
(field names, observed values) and are not a stable contract.
| Trigger | Code | Message |
|---|---|---|
prompt missing / empty | 20002 | prompt is required |
prompt longer than 4,000 chars | 20007 | prompt must be at most 4000 characters |
Unknown size value | 20003 | invalid size "..." (allowed: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 5:4, 4:5, 2:1, 1:2, 21:9, 9:21, auto, or WxH pixels) |
Unknown resolution value | 20003 | invalid resolution "..." (allowed: 1k, 2k, 4k) |
4k with non-widescreen / auto / no size | 20003 | 4K requires an explicit size in {16:9, 9:16, 2:1, 1:2, 21:9, 9:21} |
n outside 1–4 | 20003 | n must be between 1 and 4 |
image_urls > 16 | 20003 | image_urls accepts at most 16 entries |
mask_url without image_urls | 20003 | mask_url requires at least one entry in image_urls |
Any URL field carrying a data: URI | 20003 | image URL must be a public http(s) URL — data: URIs are rejected (or mask_url must be a public URL …) |
Unknown quality / background / moderation | 20003 | invalid <field> "..." (allowed: …) |
The full envelope is { "error": { "code", "message", "request_id" } } —
see Errors catalog for the wire format and
request_id correlation.
Recipes
Text-to-image — minimal
{
"model": "gpt-image-2-official",
"prompt": "ancient castle beneath a starry sky"
}2K poster
{
"model": "gpt-image-2-official",
"prompt": "cyberpunk night cityscape",
"size": "16:9",
"resolution": "2k",
"quality": "high"
}4K wallpaper
{
"model": "gpt-image-2-official",
"prompt": "panoramic snow-capped mountains at sunrise",
"size": "16:9",
"resolution": "4k",
"quality": "high"
}Multi-reference fusion (image-to-image)
{
"model": "gpt-image-2-official",
"prompt": "blend the two references into one cohesive illustrated poster",
"size": "1:1",
"quality": "high",
"image_urls": [
"https://your-cdn.com/input-a.png",
"https://your-cdn.com/input-b.png"
]
}Mask-based inpainting
The mask must match the dimensions of the first image_urls entry
and carry an alpha channel where the model should paint.
{
"model": "gpt-image-2-official",
"prompt": "replace the background with a desert sunset",
"size": "1:1",
"quality": "medium",
"image_urls": ["https://your-cdn.com/photo.png"],
"mask_url": "https://your-cdn.com/mask.png"
}Batch of 4 variations
{
"model": "gpt-image-2-official",
"prompt": "four minimalist poster variations of a red fox",
"size": "1:1",
"quality": "low",
"n": 4
}Lenient moderation
{
"model": "gpt-image-2-official",
"prompt": "moody noir portrait, dramatic lighting",
"size": "4:5",
"resolution": "2k",
"quality": "high",
"moderation": "low"
}Polling pattern
Latency depends heavily on quality and resolution:
quality × resolution | Typical end-to-end |
|---|---|
low × 1k | 20 – 40 s |
medium × 1k | 30 – 60 s |
high × 2k | 60 – 120 s |
high × 4k | 120 – 180 s |
Recommended cadence:
0–30s: wait before the first poll
30s–3m: poll every 3–5s
3m+: back off to 10s; cap at 30sSet client-side request timeouts to ≥ 180 seconds when using
quality: "high" with 2k / 4k.
The worker's wall-clock cap is 1 hour (image tasks), comfortably above any realistic queue.
Pricing
Per-image rates depend on three axes:
- Resolution (
1k/2k/4k) - Quality (
low/medium/high—autobills athigh) size(the2k/4kcells charge slightly more for the widest ratios; live numbers on the model page are authoritative)
When size is "auto", reAPI prices against the most expensive
ratio at the resolved (resolution, quality) cell so the bill never
undershoots once the upstream picks a ratio at runtime. The forwarded
body keeps auto — the override is billing-only.
Bill formula (1 credit = $0.001):
credits = ceil(per_image_usd × n × 1000)Charged on submit; refunded automatically on failed /
provider_submit_failed / provider_polling_timeout. Moderated
prompts return 400 before charging — no balance impact.
Worked example. n: 2, resolution: "2k", quality: "high",
size: "16:9" charges 2× the 16:9@2k_high cell. Rates evolve;
check the model page for
live numbers.
Tips
- Specify ratio in
size, not in the prompt. Repeating "16:9 wide shot" inside the prompt confuses the upstream. Usesizefor shape and the prompt for content / style. - Set
qualityexplicitly to save money.autoruns athigh— ifmediumis good enough, send"medium"and pay the medium rate. - Batches are linear cost.
n: 4is exactly 4× the price ofn: 1at the same parameters — no batch discount, but no batch surcharge either. - Mask alpha matters. The mask's transparent regions are where the
model paints; opaque regions are preserved. A fully opaque mask
returns
400from upstream. - Pre-cache reference images. The upstream fetches each
image_urlsentry once per submit; if your CDN is slow, latency shows up as polling time, not as billing.
Differences from gpt-image-2
| Feature | gpt-image-2 | gpt-image-2-official (this page) |
|---|---|---|
| Endpoint | /api/v1/images/generations | /api/v1/images/generations |
| Async / task model | ✅ | ✅ |
size enum (14) | ✅ | ✅ |
Resolution tiers (1k / 2k / 4k) | ✅ | ✅ |
Image-to-image (image_urls) | ✅ | ✅ |
| Pricing | flat per resolution | varies by resolution × quality × ratio — see model page |
Batch (n > 1) | ❌ | ✅ up to 4 |
| Quality tiers | ❌ | ✅ auto / low / medium / high |
Mask inpainting (mask_url) | ❌ | ✅ |
| Background control | ❌ | ✅ (transparent silently downgraded) |
| Moderation knob | ❌ (default) | ✅ auto / low |
Related
gpt-image-2— cheaper variant, single image, flat per-resolution pricing- Errors catalog
- Authentication
- Quickstart
- Pricing — gpt-image-2