This is an upscaled variant: 2K and 4K images are generated smaller and then upscaled to the target size, so fine detail and texture are below native 2K / 4K. It suits test runs, bulk previews and images where fine detail is not critical. For print-level detail, legible small text or native 4K, use gpt-image-2.
Text-to-image and image editing with the same request format as gpt-image-2. 1K / 2K / 4K output. Async: POST creates a task, then poll with GET ?task_id= or supply a callback_url.
Add the Authorization header with your API key to every request:
Authorization: Bearer YOUR_API_KEY
| Resolution | Price per image | Output |
|---|---|---|
| 1K | $0.01 | Around 1 megapixel (e.g. 1024x1024 for 1:1) |
| 2K | $0.015 | Generated smaller, upscaled to 2K |
| 4K | $0.02 | Generated smaller, upscaled to 4K |
USD per image. The price depends only on resolution, not on quality, aspect ratio or prompt length. Failed requests are not charged.
/api/v1/images/generationsCreate an image task (text-to-image, or editing when reference images are provided).
/api/v1/images/generations?task_id=xxxQuery task status and get the image URL.
| Resolution | aspect_ratio |
|---|---|
| 1K | 1:1 / 2:3 / 3:2 / 4:5 / 5:4 / 4:3 / 3:4 / 16:9 / 9:16 / 21:9 |
| 2K | 1:1 / 2:3 / 3:2 / 4:3 / 3:4 / 16:9 / 9:16 / 21:9 |
| 4K | 1:1 / 2:3 / 3:2 / 4:3 / 3:4 / 16:9 / 9:16 / 21:9 |
5:4 and 4:5 are supported at 1K only. At 2K / 4K use 1K instead, or switch to 4:3 / 3:4.
# Create task: 2K, 16:9 text-to-image
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-upscaled",
"prompt": "A cherry blossom tree by a tranquil river at dawn, soft light",
"aspect_ratio": "16:9",
"resolution": "2K"
}'
# Response:
# { "code": 200, "msg": "success", "data": { "taskId": "clxxx...", "state": "pending" } }
# Poll task status
curl "https://api.apimodels.app/v1/images/generations?task_id=TASK_ID" \
-H "Authorization: Bearer YOUR_API_KEY"{
"code": 200,
"msg": "success",
"data": {
"taskId": "clxxx...",
"state": "pending"
}
}{
"code": 200,
"msg": "success",
"data": {
"taskId": "clxxx...",
"state": "completed",
"resultUrls": ["https://r2.apimodels.app/images/xxx.png"],
"costTime": 14320,
"completeTime": 1705123465000
}
}{
"code": 200,
"msg": "success",
"data": {
"taskId": "clxxx...",
"state": "failed",
"failMsg": "Content policy violation"
}
}Pass callback_url in the create request. When the task reaches the completed or failed state, our server sends an HTTP POST to that URL with Content-Type: application/json (no signing header). Delivery is retried up to 3 times with exponential backoff (10s timeout per attempt); if still unsuccessful, a background job keeps retrying for up to 30 minutes until your endpoint returns 2xx.
POST {your callback_url}
Content-Type: application/json
{
"code": 200,
"msg": "success",
"data": {
"taskId": "clxxx...",
"model": "gpt-image-2-upscaled",
"state": "completed" | "failed",
"param": "<JSON string>", // request params, JSON.parse once
"resultJson": "<JSON string> | null", // result object, JSON.parse once
"failCode": null | "string",
"failMsg": null | "string",
"costTime": 14320, // duration in ms
"completeTime": 1705123465000, // ms epoch
"createTime": 1705123450000 // ms epoch
}
}Note: data.param and data.resultJson are JSON strings. Call JSON.parse once on each. After parsing, resultJson is { "resultUrls": ["https://..."] }; when state=failed it is usually null or {"resultUrls":[]}.
pendingTask queuedprocessingImage is being generatedcompletedDone, resultUrls availablefailedFailed, not charged400Bad Request - missing or invalid parameters401Unauthorized - invalid API key402Payment Required - insufficient credits404Not Found - task ID not found500Internal Server Error