Overview
operation is an ordinary JSON field and must be generation, edit, or variation. Tasks are made durable before execution. If the network outcome is unknown, inspect the original task instead of submitting again with a new idempotency key.
This endpoint may incur a real charge. The explorer first verifies the public price for matching route rows from the current same-origin model detail, then requires your explicit confirmation.
Request
Request headers
| Name | Type | Description |
|---|---|---|
Idempotency-Keyrequired | string | Required for every mutation. Reuse the same value for the same business intent to prevent duplicate charges. |
JSON request body
| Field | Type | Description |
|---|---|---|
operationrequired | generation | edit | variation | Select the operation explicitly; OGA does not guess. |
modelrequired | string | Published logical model ID. |
prompt | string | Prompt; requirement and maximum length depend on model-operation capabilities. |
images | string[] | Ordered HTTPS URLs or MIME-qualified image data URLs. |
mask | string | One optional edit mask, subject to model capability and dimension rules. |
n | integer | Requested result count, default 1; read the maximum from model details. |
size | string | Pixel dimensions or ratio; it must match an exact published route-row value. |
size_tier | 1k | 2k | 4k | Resolution tier for selected models; together with size it must form a published pair. |
quality | string | Quality tier; support depends on the final route row. |
response_mode | async | sync | Defaults to async. sync waits up to 60 seconds, then returns the same durable task. |
response_format | url | b64_json | Result representation, default url. |
Python and TypeScript
Examples contain placeholders only and never retry automatically. Production code should read the OGA key from a secure environment and create a unique idempotency key and request ID for every business operation.
Python · httpx
import os
import httpx
response = httpx.post(
os.environ["OGA_BASE_URL"] + "/api/v1/images/tasks",
headers={
"Authorization": "Bearer <YOUR_OGA_API_KEY>",
"Content-Type": "application/json",
"Idempotency-Key": "<UNIQUE_IDEMPOTENCY_KEY>",
"X-Request-Id": "<UUID_V4>",
"Accept-Language": "en-US",
},
json={
"model": "gpt-image-2",
"operation": "generation",
"prompt": "A quiet blue observatory above the clouds",
"n": 1,
"size": "1024x1024",
"quality": "standard",
"response_format": "url",
"response_mode": "async"
},
timeout=30,
)
response.raise_for_status()
print(response.json())TypeScript · fetch
const response = await fetch(
`${process.env.OGA_BASE_URL}/api/v1/images/tasks`,
{
method: "POST",
redirect: "error",
headers: {
"Authorization": "Bearer <YOUR_OGA_API_KEY>",
"Content-Type": "application/json",
"Idempotency-Key": "<UNIQUE_IDEMPOTENCY_KEY>",
"X-Request-Id": "<UUID_V4>",
"Accept-Language": "en-US",
},
body: JSON.stringify(
{
"model": "gpt-image-2",
"operation": "generation",
"prompt": "A quiet blue observatory above the clouds",
"n": 1,
"size": "1024x1024",
"quality": "standard",
"response_format": "url",
"response_mode": "async"
}
),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
console.log(await response.json());Response
JSON endpoints use the standard response envelope. HTTP status represents the request outcome; business errors are not disguised as HTTP 200.
| HTTP | Meaning |
|---|---|
200 | Request succeeded |
202 | Task is durable and continues asynchronously |
400 | Invalid business parameter or filter |
401 | Missing or invalid API key |
402 | Insufficient balance; billable task not accepted |
403 | API key disabled or access forbidden |
409 | Idempotency or current-state conflict |
422 | Request-structure validation failed |
500 | Internal service error |
Complete success example (optional fields vary by state)
{
"code": 0,
"message": "success",
"data": {
"task_id": "task_01JEXAMPLE",
"status": "queued",
"terminal_reason": null,
"model": "gpt-image-2",
"operation": "generation",
"size": "1024x1024",
"size_tier": null,
"quality": "standard",
"response_format": "url",
"input_count": 0,
"has_mask": false,
"response_mode": "async",
"auto_async_on_timeout": null,
"requested_count": 1,
"result": null,
"result_expires_at": null,
"result_expired": false,
"poll_url": "/api/v1/tasks/task_01JEXAMPLE",
"retry_after_seconds": 5,
"channel": null,
"routing": {
"strategy": "stable_first",
"total_attempts": 0,
"switch_count": 0,
"attempts": []
},
"error": null,
"billing": {
"status": "held",
"currency": "USD",
"reserved_amount": "0.023000",
"charged_amount": "0.000000",
"refunded_amount": "0.000000",
"released_amount": "0.000000",
"balance_after_settlement": null
},
"created_at": "2026-08-10T00:00:00Z",
"updated_at": "2026-08-10T00:00:00Z",
"completed_at": null
},
"request_id": "8f25b42f-2ed1-4ad7-99de-61d7f779bc7b",
"timestamp": "2026-08-10T00:00:00Z"
}Important boundaries
- This is the only billable POST in the common-endpoint guide; generations, edits, and variations aliases do not exist.
- A request may incur a real charge. The public price snapshot locked at submission is authoritative.
- Unknown upstream acceptance never triggers a route switch or automatic resubmission.
- The explorer never accepts a custom size from WIDTHxHEIGHT syntax alone; it must also satisfy custom_size_constraints published by a current routable route.