Image Generation API
Generate or edit images with the OpenAI-compatible Images endpoints and see the request and response formats.
The API domain is https://api.flatrouter.com. Send a prompt to POST /v1/images/generations. You can also upload images to POST /v1/images/edits to edit them. Image results are returned in the same request. For long-running requests, use asynchronous tasks and poll for the result.
Before you start
Create an API key under Console → API Keys, choosing a group that supports your image model and has image generation enabled. Authenticate with Authorization: Bearer <API Key>.
Image generation
Replace YOUR_FLATROUTER_API_KEY with your API key:
curl https://api.flatrouter.com/v1/images/generations \
-H "Authorization: Bearer YOUR_FLATROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "An orange cat sitting by a window, watercolor illustration",
"n": 1,
"response_format": "b64_json"
}'| Parameter | Description |
|---|---|
model | Image model; this example uses gpt-image-2 |
prompt | A description of the image to generate |
n | Number of images; this example requests 1 |
response_format | This example uses b64_json to return Base64-encoded image data |
You can also use gpt-image-2.5-flare or gpt-image-2.5-sunburst; available models depend on the group associated with your API key.
Image editing
Send a multipart/form-data request to POST /v1/images/edits. Replace the API key and /path/to/source.png with your local input image path:
curl -X POST https://api.flatrouter.com/v1/images/edits \
-H "Authorization: Bearer YOUR_FLATROUTER_API_KEY" \
-F "image=@/path/to/source.png;type=image/png" \
-F "model=gpt-image-2" \
-F "prompt=Change the background to a beach, keeping the subject" \
-F "response_format=b64_json"curl -F sets the Content-Type and multipart boundary automatically; do not add them manually.
| Parameter | Description |
|---|---|
image | The image file to edit; repeat the image[] file field for multiple inputs |
prompt | Required; describe the changes to make to the input image |
model | Image model; this example uses gpt-image-2, and available models depend on your group |
response_format | This example uses b64_json to return Base64 image data |
mask | Optional mask file uploaded as a multipart file field; specific requirements depend on the model |
Editing and generation share the response format below.
Response format
This is an example of a non-streaming response, with image data omitted:
{
"created": 1788912000,
"data": [
{
"b64_json": "<Base64 image data>"
}
]
}created is the response Unix timestamp in seconds, and data is the array of image results. The single image requested above is in data[0].b64_json; decode it from Base64 to obtain the image file contents. The response may include additional fields.
Asynchronous tasks
Generating high-resolution or multiple images can take a while. If your client, proxy, or gateway enforces a timeout on individual HTTP requests, use the asynchronous endpoints instead: submit a task, get a task ID immediately, then poll for the result without holding a connection open.
| Method and path | Description |
|---|---|
POST /v1/images/generations/async | Submit a generation task; the request body is identical to /v1/images/generations |
POST /v1/images/edits/async | Submit an edit task; the multipart/form-data request body is identical to /v1/images/edits |
GET /v1/images/tasks/{task_id} | Query task status and result |
Model selection, group permissions, and billing are the same as the synchronous endpoints. The asynchronous endpoints do not support streaming; do not set "stream": true in the request.
Submit a task
Append /async to the synchronous endpoint path; the request body is unchanged:
curl https://api.flatrouter.com/v1/images/generations/async \
-H "Authorization: Bearer YOUR_FLATROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "An orange cat sitting by a window, watercolor illustration",
"n": 1
}'A successful submission returns HTTP 202 Accepted:
{
"id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"task_id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"object": "image.generation.task",
"status": "processing",
"created_at": 1788912000,
"expires_at": 1788998400,
"poll_url": "/v1/images/tasks/imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60"
}poll_url is the polling path; prepend https://api.flatrouter.com to use it, and the Location response header carries the same path. Problems such as invalid request parameters or a group without image generation enabled return an error at submission time — no task is created.
Poll a task
Poll with the same API key that submitted the task:
curl https://api.flatrouter.com/v1/images/tasks/imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60 \
-H "Authorization: Bearer YOUR_FLATROUTER_API_KEY"The polling endpoint returns HTTP 200; read the task state from the status field:
status | Meaning |
|---|---|
processing | Still generating; poll again later |
completed | Done; the result is in result |
failed | Failed; the reason is in error |
Response when the task completes:
{
"id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"task_id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"object": "image.generation.task",
"status": "completed",
"http_status": 200,
"image_url": "https://img.flatrouter.com/<image-path>",
"result": {
"created": 1788912095,
"data": [
{
"url": "https://img.flatrouter.com/<image-path>"
}
]
},
"created_at": 1788912000,
"completed_at": 1788912095,
"expires_at": 1788998495
}result has the same format as the synchronous response, except that images are returned as links: each image URL is in result.data[].url, and b64_json is not included (even if the request sets "response_format": "b64_json"). image_url is the link to the first image, convenient when only one image is generated.
Response when the task fails:
{
"id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"task_id": "imgtask_3f2a9c1e8b7d4a6f9e0c1b2a3d4e5f60",
"object": "image.generation.task",
"status": "failed",
"http_status": 502,
"error": {
"type": "api_error",
"message": "Upstream request failed"
},
"created_at": 1788912000,
"completed_at": 1788912095,
"expires_at": 1788998495
}http_status is the HTTP status code of that generation attempt, and error has the same format as the synchronous endpoint's error object.
Polling guidance and limits
- Poll once every 3 seconds. While the task is
processing, theRetry-Afterresponse header suggests an interval in seconds. - A single task runs for at most 30 minutes; on timeout its status becomes
failed. - Task records are retained for 24 hours after the last status change (see
expires_at); queries after expiry return404. Download and save image links promptly. - A task can only be queried by the API key that submitted it; a task ID that does not exist, has expired, or belongs to another API key (including other keys under the same account) returns
404.