OpenAI-compatible sync image API for GPT Image 2 — point the OpenAI SDK, Codex, or Cursor at our base_url and it works as-is. Full resolution × quality matrix (1K/2K/4K × low/medium/high/auto), text-to-image plus multi-image editing (up to 16 reference images + mask), synchronous responses with no polling.
All requests carry the API key in the header:
Authorization: Bearer YOUR_API_KEY| Field | Required | Type | Description |
|---|---|---|---|
| Tier | low | medium / auto | high |
| 1K | $0.01 | $0.025 | $0.07 |
| 2K | $0.025 | $0.03 | $0.10 |
| 4K | $0.05 | $0.05 | $0.23 |
Billed per image; quality=auto is charged at the medium tier; failed requests are not charged. Speed scales with quality: low ~40s, medium ~60-90s, high ~2 minutes.
| Field | Required | Type | Description |
|---|---|---|---|
| Tier | Typical sizes | Tier rule | |
| 1K | 1024x1024 / 1536x1024 / 1024x1536 | long edge ≤ 1536 | |
| 2K | 2048x2048 / 2048x1152 / 1152x2048 | long edge 1537-2048 | |
| 4K | 3840x2160 / 2160x3840 | long edge > 2048 |
Arbitrary WxH is also supported: both sides multiples of 16, long edge ≤ 3840, aspect ratio ≤ 3:1, total pixels 655K-8.29M. Alternatively omit size and pass aspect_ratio + resolution (1K/2K/4K) and the server derives the best size.
/api/v1/images/generations·POST/api/v1/images/editsPassing an OpenAI-style WxH size triggers sync mode: the response carries the image inline (b64_json + url), matching the official images.generate() / images.edit() contract.
# Text-to-image — OpenAI Images API shape, SYNC response (no task polling)
curl -X POST https://api.apimodels.app/v1/images/generations \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2-all",
"prompt": "a white sneaker product shot on beige background, studio light",
"size": "2048x2048",
"quality": "medium",
"n": 1
}'
# → { "created": ..., "data": [{ "b64_json": "...", "url": "https://r2.apimodels.app/..." }] }
# Image edit / multi-image fusion — multipart, OpenAI images.edit() shape
curl -X POST https://api.apimodels.app/v1/images/edits \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "model=gpt-image-2-all" \
-F "image=@product.png" \
-F "prompt=put this sneaker on a model, e-commerce close-up" \
-F "size=2048x2048" \
-F "quality=medium"Sync mode: waiting and timeouts (since 2026-08-27)
A sync request waits up to 280 seconds. If the image is not ready after about 95 seconds, the server sends the HTTP 200 headers and writes one space every 15 seconds to keep the connection alive, then appends the full JSON once the image is ready (leading whitespace is valid JSON; every parser and the OpenAI SDK handle it as-is). 2K/4K high renders that take 2–3 minutes are therefore no longer cut off with a gateway 524.
The trade-off: once the headers are sent the status code cannot change. If the task fails after the 95-second mark (for example an upstream content filter rejecting the finished image), the response is still HTTP 200 and the error is carried in the body as {"error": {"code": ..., "message": ..., "task_id": ...}} with no data field. Check the error field as well as the status code. Failures within 95 seconds return real status codes: content moderation 400 (code content_policy_violation), invalid input 400, insufficient balance 402, upstream busy 503, upstream failure 502, timeout 504.
Every sync response carries an x-apimodels-task-id header. If your client disconnects on its own timeout, use it with GET /v1/images/generations?task_id=... to fetch the result; the task is neither cancelled nor billed twice because of the disconnect.
Pass stream: true to use the OpenAI image streaming contract (SSE) instead: ": processing Ns" comment lines while waiting, an image_generation.completed / image_edit.completed event (with b64_json and url) on success, and an error event on failure. This path has none of the status-code limitation above and is the recommended option if you can change one line. Renders budgeted beyond two minutes can also use the native async contract in Option 2.
Without a WxH size (or when you need callback_url) the request follows the platform async contract: create returns a taskId; poll until completed, or receive a webhook callback.
# Native async contract — pass aspect_ratio + resolution tier instead of size.
curl -X POST https://api.apimodels.app/v1/images/generations \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2-all",
"prompt": "a lighthouse on a cliff at dusk",
"aspect_ratio": "9:16",
"resolution": "2K",
"quality": "medium",
"callback_url": "https://your-domain.com/webhook"
}'
# → { "code": 200, "data": { "taskId": "..." } }
curl "https://api.apimodels.app/v1/images/generations?task_id=TASK_ID" \
-H "Authorization: Bearer YOUR_API_KEY"| Field | Required | Type | Description |
|---|---|---|---|
| Field | Type | Description | |
| model | string | gpt-image-2-all | |
| prompt | string | Prompt (required) | |
| size | string | WxH — triggers sync mode; see the size table | |
| quality | string | low / medium / high / auto (default medium; auto billed as medium) | |
| aspect_ratio + resolution | string | Async alternative to size: ratio + 1K/2K/4K tier | |
| image / image_base64 / image_url | string | Reference image → auto-routes to the edit endpoint | |
| image_urls / images | string[] | Multi-image fusion, up to 16 | |
| mask / mask_url / mask_base64 | string | Mask inpainting: a PNG the same size as the image; transparent pixels mark the area to repaint. ⚠️ The upstream model currently honors the mask inconsistently: in our tests roughly half of requests apply it correctly, the rest repaint the whole image or return it unchanged, and we cannot detect this server-side in advance. Requests where the mask was not honored are eligible for a refund via support@apimodels.app. | |
| background | string | transparent / opaque / auto | |
| output_format | string | png / jpeg / webp (optional). If omitted: opaque images are delivered as JPEG q95, images with an alpha channel stay PNG. Pass png for the lossless original — about 6x the size of the JPEG (measured on a 1760x2352 render: PNG 6.6MB vs JPEG 1.0MB); webp is JPEG-sized and keeps transparency. | |
| response_format | string | b64_json (default) or url (edits endpoint) | |
| stream | boolean | Sync mode only: return an SSE stream instead (see the note above) | |
| moderation | string | Accepted but ignored. Content filtering is applied upstream at a fixed level and cannot currently be relaxed per request or per account. | |
| n | number | Number of images (billed × n) |
Try it in the Playground
Up to 16 reference images for multi-image fusion / editing; anything beyond 16 uses the first 16. Pass them as images[] (or a single image).
Native 1K / 2K / 4K, priced $0.025 / $0.03 / $0.05 per image. Charged only on success.