Image Generation

POST /v1/images/generations

OpenAI-compatible image generation. The primary model is gpt-image-2. Two modes are supported:

  • Synchronous — the request blocks until the image is ready and returns it directly (best for low concurrency / interactive use).
  • Asynchronous — submit and immediately receive a job ID, then poll for the result (best for high volume / avoiding long-held connections).

Synchronous: POST /v1/images/generations

Request parameters

Parameter Type Required Description
model string Yes Model ID, e.g. gpt-image-2.
prompt string Yes Text prompt describing the image.
n integer No Number of images. Only 1 is currently supported (default 1).
size string No Image size, e.g. 1024x1024, 1536x1024 (supported by gpt-image-2; not all models).
quality string No Quality hint (supported by gpt-image-2; not all models).

Note: gpt-image-2 does not accept response_format; the gateway drops it automatically, so you don't need to send it.

Example

cURL

curl https://api.portal.aiin1.ai/v1/images/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "a red fox running in snow, studio lighting",
    "n": 1
  }'

Python

import openai
 
client = openai.OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.portal.aiin1.ai/v1",
)
 
resp = client.images.generate(
    model="gpt-image-2",
    prompt="a red fox running in snow, studio lighting",
    n=1,
)
b64 = resp.data[0].b64_json   # base64-encoded PNG

Response

The image is returned inline as base64:

{
  "created": 1730000000,
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...",
      "revised_prompt": "..."
    }
  ]
}

To display in a browser, prefix it: data:image/png;base64,<b64_json>.


Asynchronous: POST /v1/images/generations/async

The request body is identical to the synchronous route (model / prompt / n / size / quality), but it returns a job ID immediately instead of blocking. Use this for batch generation or when the client shouldn't hold a long connection open.

1. Submit

curl https://api.portal.aiin1.ai/v1/images/generations/async \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "a red fox running in snow",
    "n": 1
  }'

Returns 202 Accepted:

{
  "id": "nximg_xxxxxxxx",
  "status": "queued",
  "created": 1730000000,
  "object": "image.generation.async"
}

2. Poll: GET /v1/images/generations/async/{job_id}

curl https://api.portal.aiin1.ai/v1/images/generations/async/nximg_xxxxxxxx \
  -H "Authorization: Bearer YOUR_API_KEY"

status transitions: queuedprocessingsucceeded (or failed). Poll every 1–2 seconds; generation usually takes seconds to tens of seconds.

In progress:

{ "id": "nximg_xxxxxxxx", "status": "processing", "created": 1730000000 }

Succeeded:

{
  "id": "nximg_xxxxxxxx",
  "status": "succeeded",
  "created": 1730000000,
  "data": [
    {
      "url": "https://<bucket>.r2.cloudflarestorage.com/...&X-Amz-Signature=...",
      "revised_prompt": "..."
    }
  ]
}

Failed:

{
  "id": "nximg_xxxxxxxx",
  "status": "failed",
  "created": 1730000000,
  "error": { "type": "upstream_error", "message": "generation failed", "code": "..." }
}

About url: unlike the synchronous route (inline base64), the async route returns a signed download URL on success (valid for ~2 hours). Download or re-host it within the validity window; an expired URL requires regenerating. Failed jobs are not billed.

Field reference

Field Description
id Job ID (nximg_ prefix), used for polling. Bound to your API key's organization — others cannot access it.
status queued / processing / succeeded / failed.
data[].url Signed image download URL on success (~2h validity).
data[].revised_prompt Model-revised prompt (may be empty).