Flatrouter

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"
  }'
ParameterDescription
modelImage model; this example uses gpt-image-2
promptA description of the image to generate
nNumber of images; this example requests 1
response_formatThis 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.

ParameterDescription
imageThe image file to edit; repeat the image[] file field for multiple inputs
promptRequired; describe the changes to make to the input image
modelImage model; this example uses gpt-image-2, and available models depend on your group
response_formatThis example uses b64_json to return Base64 image data
maskOptional 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 pathDescription
POST /v1/images/generations/asyncSubmit a generation task; the request body is identical to /v1/images/generations
POST /v1/images/edits/asyncSubmit 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:

statusMeaning
processingStill generating; poll again later
completedDone; the result is in result
failedFailed; 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, the Retry-After response 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 return 404. 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.

On this page