Skip to Content
API referenceOpenAI CompatibleImages

Images API

Two endpoints: Generate (text → image) and Edit (image + text → image). Both responses follow the OpenAI standard shape data[0].b64_json.

What you want to doEndpointSupported models
Generate an image from textPOST /v1/images/generationsGPT Image, Nano Banana (Gemini), Seedream, Qwen-Image and MAI Image families
Upload an image and edit it with a promptPOST /v1/images/editsGPT Image, Nano Banana (Gemini), MAI Image

Seedream and Qwen-Image do not support /v1/images/edits; for image-to-image they use the generations endpoint, but with different reference-image fields: Seedream uses image, Qwen uses input_images — don’t mix them up. When you need to control Gemini’s resolution (512 to 4K), use the Gemini native protocol. Parameter differences for each family are covered on its family page.

Quickstart

A minimal runnable request: generate one 1024×1024 image and save it as output.png.

base_urlhttps://api.ofox.io/v1
Generate endpointhttps://api.ofox.io/v1/images/generations
Edit endpointhttps://api.ofox.io/v1/images/edits
Model IDopenai/gpt-image-2.5-flare
gen.py
import base64 from openai import OpenAI client = OpenAI( api_key="YOUR_OFOX_API_KEY", base_url="https://api.ofox.io/v1", timeout=600, # the images API is synchronous and can be slow ) resp = client.images.generate( model="openai/gpt-image-2.5-flare", prompt="A red apple on a white table", size="1024x1024", quality="low", ) with open("output.png", "wb") as f: f.write(base64.b64decode(resp.data[0].b64_json))

The API is synchronous — set your client timeout to 600 seconds. High-quality, large-size and editing requests may take several minutes; see measured latency.

All families are called the same way — only model changes. Accepted values and family-specific parameters differ; see each parameter below.

Generate images

POST https://api.ofox.io/v1/images/generations

Request parameters

Values and defaults below apply to the GPT Image family (gpt-image-2.5-flare, gpt-image-2.5-sunburst, gpt-image-2). Where other families differ, it says so. Measured details: GPT Image family.

Required
modelrequiredstring

Model ID; case-sensitive — a wrong ID returns 404 model_not_found.

▸ Details

Supported models are listed in the table at the top of this page. Use the full ID with its vendor prefix, e.g. openai/gpt-image-2.5-flare.

promptrequiredstring

Describes the image to generate.

Common
sizestring· default auto· valuesWIDTHxHEIGHTauto

Output size. Custom sizes must meet four rules, or you get 400 Invalid size.

▸ Details

The four rules:

  • Width and height both divisible by 16
  • Longest edge ≤ 3840
  • Aspect ratio between 1:3 and 3:1
  • Total pixels ≥ 655,360 (768x768 is rejected, 1024x768 is fine)

Omitted or auto, the model decides — we measured 1254×1254. Pass a size explicitly if you need a fixed one. Other families have different size rules; see their family pages. Details: GPT Image · size.

qualitystring· valueslowmediumhighxhighmaxauto

Quality tier; it directly drives the price. gpt-image-2 has no xhigh / max.

▸ Details
  • gpt-image-2 has no xhigh / max — they return 400.
  • The DALL·E-era standard / hd are not accepted — they return 400.
  • Omitting it is not the same as medium: the model picks a tier (we measured low). Set it explicitly for stable quality and cost.

Most other families have no tiers; see their family pages. Details: GPT Image · quality.

ninteger· default 1· values1–10

Number of images; each is billed separately. Not supported by Gemini models — do not send it.

output_formatstring· default png· valuespngjpegwebp

Output file format.

▶Advanced · 7output_compression · background · moderation · stream · partial_images · input_images · extra_body.provider.typeExpand
output_compressioninteger· values0–100

Compression level; jpeg / webp only.

backgroundstring· default opaque· valuesopaquetransparentauto

Background. transparent needs a format with an alpha channel (png / webp).

moderationstring· valuesautolow

Moderation strictness.

streamboolean· valuestruefalse

Stream the response. With partial_images you receive intermediate images during generation.

partial_imagesinteger· values0–3

Number of intermediate images to stream; requires stream: true. Per OpenAI’s docs, each partial image adds 100 output tokens.

input_imagesstring[]· values1–3 images

Array of reference images (URL or base64), Qwen family only, 1–3 images.

▸ Details

Other families accept it without an error but ignore it; Seedream’s reference-image field is image.

extra_body.provider.typestring· valuesazure_foundryopenai

Selects a provider. Optional and usually unnecessary — the gateway routes automatically. Consider it when you have content moderation requirements; once a provider is selected, requests will not fall back to another provider if it is unavailable.

▸ Details

The header X-OfoxAI-Provider-Type is equivalent. See Advanced: pinning a provider.

Response

200 OK (b64_json truncated)
{ "created": 1777385517, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…", "index": 0 } ], "model": "openai/gpt-image-2.5-flare", "size": "1024x1024", "quality": "low", "usage": { "input_tokens": 13, "input_tokens_details": { "text_tokens": 13 }, "output_tokens": 196, "output_tokens_details": { "image_tokens": 196 }, "total_tokens": 209 } }

The image as base64, without a data:image/png;base64, prefix.

▸ Details

Decode it and write the file; to display it in a browser, add the prefix yourself. There is no url field in the response.

Image index; distinguishes images when n > 1.

sizestring

The actual output size. When size was omitted or auto, read the real size here.

qualitystring

The tier actually used. When quality was omitted, this tells you which tier was used.

The background and format actually used. Not always present — do not depend on them.

usageobject

Billing usage. output_tokens is the output image tokens; input_tokens_details.text_tokens is the prompt tokens.

▸ Details

Compute the cost of a call from these numbers.

Edit images

POST https://api.ofox.io/v1/images/edits

This endpoint supports GPT Image, Nano Banana (Gemini) and MAI Image. Seedream and Qwen-Image return 400 endpoint_not_supported here; use the reference-image field on the generations endpoint instead — see Seedream and Qwen-Image.

Request parameters

Sent as multipart/form-data form fields, with an uploaded image file. Values and defaults again apply to the GPT Image family.

Required
modelrequiredstringform

Model ID; same rules as generations. Supported models are listed in the table at the top of this page.

imagerequiredfileform· valuesPNGJPEG

Reference image as a local file (@ prefix in cURL), not a URL.

▸ Details

For several, repeat the field as image[]. ≤ 15 MB each, ≤ 50 MB request body; the gateway sets no count limit, 16 or fewer recommended.

promptrequiredstringform

The edit instruction.

Common
maskfileform· valuesPNG with alpha

Inpainting mask: a PNG with an alpha channel, the same size as image; transparent area = what gets repainted.

▸ Details

Only effective on this endpoint — silently ignored on generations. How to build one and the measured effect: GPT Image · mask inpainting.

sizestringform· default auto· valuesWIDTHxHEIGHTauto

Output size; same rules as generations.

▸ Details

Omitted or auto, the model decides — not guaranteed to match the input. Pass it explicitly to keep the original size.

qualitystringform· valueslowmediumhighxhighmaxauto

Quality tier; same rules as generations — gpt-image-2 has no xhigh / max.

nintegerform· default 1· values1–10

Number of images; each is billed separately.

▶Advanced · 1X-OfoxAI-Provider-TypeExpand
X-OfoxAI-Provider-Typestringheader· valuesazure_foundryopenai

Selects a provider. Optional and usually unnecessary — the gateway routes automatically. Consider it when you have content moderation requirements; once a provider is selected, requests will not fall back to another provider if it is unavailable.

▸ Details

This endpoint is a multipart upload, so to pin a provider only the header works — an extra_body form field is silently ignored. See Advanced: pinning a provider.

Response

Same shape as generations; usage adds input tokens for the reference images:

200 OK (b64_json truncated)
{ "created": 1777385669, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…", "index": 0 } ], "model": "openai/gpt-image-2", "size": "auto", "quality": "low", "usage": { "input_tokens": 1041, "input_tokens_details": { "image_tokens": 1024, "text_tokens": 17 }, "num_input_images": 1, "output_tokens": 358, "total_tokens": 1399 } }

Input tokens charged for the reference images. We measured 1,024 for one 1024×1024 reference image. This is the main reason an edit costs more than same-size text to image.

Number of reference images; use it to confirm the model actually read them.

Other fields are the same as the generations response.

See supported models and pricing in the Model Catalog .

Call

edit.py
import base64 from openai import OpenAI client = OpenAI(api_key="YOUR_OFOX_API_KEY", base_url="https://api.ofox.io/v1", timeout=600) with open("apple.png", "rb") as f: resp = client.images.edit( model="openai/gpt-image-2", image=f, prompt="Make the apple green, keep everything else the same", size="auto", quality="low", ) with open("apple_edited.png", "wb") as out: out.write(base64.b64decode(resp.data[0].b64_json))

The image field takes a local file path (with the @ prefix in cURL), not a URL.

Measured before / after:

OriginalEdited
Original red appleEdited green apple

Errors

Errors come back with an HTTP error status and this body (measured):

400 Bad Request
{ "error": { "code": null, "message": "The model 'gpt-image-2' does not support quality 'xhigh'.", "param": null, "request_id": "fbe4f24c-779d-41a0-8b3a-c62886cdd1ae", "type": "image_generation_user_error" } }

code can be null. Branch on the HTTP status and message.

StatusErrorCauseFix
400Invalid size '…'Size breaks one of the four rulesAdjust per size
400does not support quality '…' or invalid valuexhigh / max sent to gpt-image-2, or standard / hd sentUse a value listed under quality
400Unknown parameter: '…'Unsupported field, e.g. DALL·E’s styleRemove the field
400Invalid image file or mode for image 1Reference image isn’t PNG / JPEG, or the mask isn’t a PNG with alpha / doesn’t match the image sizeCheck image and mask
400provider_type_unavailableThe pinned provider doesn’t serve this modelDrop the provider pin and let the gateway route
404model_not_foundModel ID misspelled or wrong caseCopy the full ID from the table on this page
429rate_limit_exceededOver 100 RPM per team; more keys don’t raise itLower concurrency, back off and retry

When contacting support, include the request_id and the error details (HTTP status and error.message) from the response. We recommend logging them.

Advanced: pinning a provider

Optional and usually unnecessary. All three GPT Image models (gpt-image-2.5-flare, gpt-image-2.5-sunburst, gpt-image-2) are served by both azure_foundry and openai, for generations and edits alike. Without a pin, the gateway routes automatically.

Select a provider when you have content moderation requirements. Requests then go only to that provider; if it is unavailable, they will not fall back to another provider automatically.

Naming a provider that does not serve the model returns 400 provider_type_unavailable.

ProviderDescriptionModeration (gpt-image-2)
azure_foundryHosted on Microsoft AzureStricter
openaiOpenAI’s own APIMore permissive

The two providers of openai/gpt-image-2 do not moderate to the same standard. If a prompt keeps getting rejected, you can pin openai explicitly. Without a pin, requests are split by weight and may land on azure_foundry.

Text to image /v1/images/generations

JSON body, so either the body field extra_body.provider.type or the header X-OfoxAI-Provider-Type works.

gen_pinned.py
resp = client.images.generate( model="openai/gpt-image-2", prompt="A simple red apple on a white table", size="1024x1024", extra_body={"extra_body": {"provider": {"type": "openai"}}}, )

With the official OpenAI SDKs, extra_body must be present as a literal key in the request body. The TypeScript SDK sends it as written in the params object. The Python SDK’s extra_body= argument merges its contents into the top level of the body, so nest it one level deeper, or use the header instead.

Image to image /v1/images/edits

A multipart upload has no JSON body to nest extra_body in, so only the header works.

Terminal
curl https://api.ofox.io/v1/images/edits \ -H "Authorization: Bearer $OFOX_API_KEY" \ -H "X-OfoxAI-Provider-Type: openai" \ -F "model=openai/gpt-image-2" \ -F "prompt=..." \ -F "image=@input.png"

With the SDKs: in Python pass extra_headers={"X-OfoxAI-Provider-Type": "openai"}; in TypeScript pass { headers: { 'X-OfoxAI-Provider-Type': 'openai' } } as the second argument.

On /v1/images/edits, extra_body sent as a form field is silently ignored: the image is generated as usual, but the constraint does not apply. Use X-OfoxAI-Provider-Type instead.

Full reference: API · Provider routing.

Official docs & further reading

The official docs describe calling OpenAI directly. Where they differ from OfoxAI’s measured behavior, the measured behavior on this site takes precedence.

OpenAI

OfoxAI family pages

Last updated on