Image Generation and Editing
OpenAI-compatible `/v1/images/generations` text-to-image and `/v1/images/edits` image-to-image, multi-image fusion, and mask-based inpainting.
Inference Space provides image capabilities compatible with the OpenAI Images API: text-to-image generation, single-image editing, multi-image fusion with up to 16 reference images, and mask-based inpainting. The primary model is currently gpt-image-2, which performs consistently with Chinese prompts, layout control, and image-text consistency, making it suitable for e-commerce hero images, posters, illustrations, and product-image compositing.
Private deployments use exactly the same API; only replace the Base domain → Enterprise private deployment.
Overview
- Text-to-image:
POST https://ai.inf.space/v1/images/generations,application/json. - Image-to-image / multi-image editing:
POST https://ai.inf.space/v1/images/edits,multipart/form-data. - Set
modeltogpt-image-2(see the model list and the console for currently available models). - Multi-image editing is the core capability: upload multiple reference images with repeated
image[]fields, then refer to them in upload order as “image 1 / image 2 / image 3” in the prompt.
The interface is compatible with the OpenAI Images API. Existing OpenAI image clients can connect by changing only the Base, Key, and model. Note that this gateway forwards only the parameters it actually supports; other OpenAI parameters are ignored. See the “Parameters” and “OpenAI compatibility” sections below for details.
Authentication and Base
- API data-plane Base:
https://ai.inf.space/v1(all/v1/*calls go toai.inf.space). - The console and API share
https://ai.inf.space; use the/v1path shown in each curl / SDK example. - Authentication header:
Authorization: Bearer $TOS_API_KEY, where the Key starts withgk_.
Create an API Key in the console and pass it in the Authorization header for each request. In production, keep the Key on the server and do not expose it in the browser. See Authentication for details.
Text-to-image
Send a JSON request to /v1/images/generations with model and prompt, plus optional size and quality. Text-to-image generates one image only, with the output format fixed to the upstream default PNG.
curl "https://ai.inf.space/v1/images/generations" \
-H "Authorization: Bearer $TOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A white ceramic mug on a gray tabletop, soft natural light, e-commerce hero-image style",
"size": "1024x1024",
"quality": "auto"
}'import os
import base64
import requests
resp = requests.post(
"https://ai.inf.space/v1/images/generations",
headers={"Authorization": f"Bearer {os.environ['TOS_API_KEY']}"},
json={
"model": "gpt-image-2",
"prompt": "A white ceramic mug on a gray tabletop, soft natural light, e-commerce hero-image style",
"size": "1024x1024",
"quality": "auto",
},
timeout=600,
)
resp.raise_for_status()
data = resp.json()
b64 = data["data"][0]["b64_json"]
with open("out.png", "wb") as f:
f.write(base64.b64decode(b64))import fs from "node:fs";
const resp = await fetch("https://ai.inf.space/v1/images/generations", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TOS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2",
prompt: "A white ceramic mug on a gray tabletop, soft natural light, e-commerce hero-image style",
size: "1024x1024",
quality: "auto",
}),
});
const data = await resp.json();
fs.writeFileSync("out.png", Buffer.from(data.data[0].b64_json, "base64"));In addition to OpenAI's standard size, text-to-image supports the gateway extensions aspectRatio (for example, "3:4", automatically aligned to a supported widthxheight at the 1K / 2K / 4K tier) and provider (to override the provider selection).
Image-to-image and multi-image editing
Send a multipart/form-data request to /v1/images/edits.
Single-image editing
Send one image field:
curl "https://ai.inf.space/v1/images/edits" \
-H "Authorization: Bearer $TOS_API_KEY" \
-F "model=gpt-image-2" \
-F "image=@product.png" \
-F "prompt=Replace the background with a pure-white e-commerce hero-image background while preserving the product details" \
-F "size=1024x1024"Multi-image editing (core capability)
Upload multiple reference images with repeated image[] fields (OpenAI array syntax), up to 16 images, each in PNG / JPEG / WebP format. Upload order determines reference order; refer to the corresponding images as “image 1 / image 2 / image 3” in the prompt.
curl "https://ai.inf.space/v1/images/edits" \
-H "Authorization: Bearer $TOS_API_KEY" \
-F "model=gpt-image-2" \
-F "image[]=@bag.png" \
-F "image[]=@scarf.png" \
-F "image[]=@model.png" \
-F "prompt=Have the model in image 3 carry the handbag from image 1 and wear the silk scarf from image 2, with an overall street-style look" \
-F "size=1024x1536"import os
import base64
import requests
files = [
("image[]", ("bag.png", open("bag.png", "rb"), "image/png")),
("image[]", ("scarf.png", open("scarf.png", "rb"), "image/png")),
("image[]", ("model.png", open("model.png", "rb"), "image/png")),
]
resp = requests.post(
"https://ai.inf.space/v1/images/edits",
headers={"Authorization": f"Bearer {os.environ['TOS_API_KEY']}"},
data={
"model": "gpt-image-2",
"prompt": "Have the model in image 3 carry the handbag from image 1 and wear the silk scarf from image 2, with an overall street-style look",
"size": "1024x1536",
},
files=files,
timeout=600,
)
resp.raise_for_status()
img = resp.json()["data"][0]["b64_json"]
open("out.png", "wb").write(base64.b64decode(img))import fs from "node:fs";
const form = new FormData();
form.set("model", "gpt-image-2");
form.set("prompt", "Have the model in image 3 carry the handbag from image 1 and wear the silk scarf from image 2, with an overall street-style look");
form.set("size", "1024x1536");
for (const name of ["bag.png", "scarf.png", "model.png"]) {
form.append("image[]", new Blob([fs.readFileSync(name)]), name);
}
const resp = await fetch("https://ai.inf.space/v1/images/edits", {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.TOS_API_KEY}` },
body: form,
});
const data = await resp.json();
fs.writeFileSync("out.png", Buffer.from(data.data[0].b64_json, "base64"));Upload order determines image numbering: the first image[] is “image 1,” the second is “image 2,” and so on. Make sure numbered references in the prompt match upload order.
Local editing (mask)
Use the mask field for inpainting: only transparent areas of the mask are redrawn, while opaque areas are preserved. mask is effective only with multipart/form-data on the edits endpoint, and the gateway forwards it unchanged to the upstream (without lossy compression, preserving the complete alpha channel).
curl "https://ai.inf.space/v1/images/edits" \
-H "Authorization: Bearer $TOS_API_KEY" \
-F "model=gpt-image-2" \
-F "image=@room.png" \
-F "mask=@room-mask.png" \
-F "prompt=Replace the masked area with a floor-to-ceiling window" \
-F "size=1024x1024"- The mask must be a PNG with an alpha channel: transparent areas = areas to redraw, opaque areas = areas to preserve.
- The mask applies to the first reference image (the first
image/image[]). - Only multipart is supported (not a JSON body); the default path and the policy-routing / failover editing paths all support it.
The mask semantics follow OpenAI gpt-image: areas with transparent alpha are redrawn, and areas with opaque alpha are preserved. The areas to redraw must therefore be transparent in the mask; do not invert them.
Output format and count
output_format(defaultpng, optionspng/jpeg/webp) is effective only on the edits endpoint and specifies the encoding format of returned images.n(number of generated images) is sent only on the edits endpoint whenn > 1; when omitted or set to 1, one image is returned. Text-to-image does not supportnand always returns one image.
curl "https://ai.inf.space/v1/images/edits" \
-H "Authorization: Bearer $TOS_API_KEY" \
-F "model=gpt-image-2" \
-F "image=@product.png" \
-F "prompt=Replace the background with a pure-white e-commerce hero-image background while preserving the product details" \
-F "size=1024x1024" \
-F "output_format=webp"Input-image compression (edits only)
For heavy multi-image fusion edits, enable lossy compression of input reference images with the x-input-image-compress: true request header. This can significantly reduce the bytes uploaded to and stored by the upstream, with nearly imperceptible quality loss. It applies only to reference images larger than 200 KB; smaller images are forwarded unchanged, and the original is retained if re-encoding produces a larger file.
curl "https://ai.inf.space/v1/images/edits" \
-H "Authorization: Bearer $TOS_API_KEY" \
-H "x-input-image-compress: true" \
-F "model=gpt-image-2" \
-F "image[]=@bag.png" \
-F "image[]=@scarf.png" \
-F "image[]=@model.png" \
-F "prompt=Have the model in image 3 carry the handbag from image 1 and wear the silk scarf from image 2, with an overall street-style look" \
-F "size=1024x1536"x-input-image-compress compresses the input image, whereas OpenAI's output_compression compresses the output image. They are different features, and this gateway currently does not support output_compression.
Parameters
The table below lists the parameters this gateway actually forwards or applies. Unlisted OpenAI parameters are ignored; see “OpenAI compatibility” below.
| Parameter | Type | Applicable interface | Required | Description |
|---|---|---|---|---|
model | string | General | Yes | Currently gpt-image-2 is the primary model |
prompt | string | General | Yes | Generation or editing instruction; Chinese is supported natively |
size | string | General | No | Target size; see the size details below |
quality | string | General | No | Defaults to auto; options are auto / low / medium / high, affecting quality and billing tier |
aspectRatio | string | Text-to-image | No | Gateway extension, such as "3:4", automatically aligned to a supported widthxheight at the selected size tier |
provider | string | Text-to-image | No | Gateway extension for overriding the provider selection |
image[] | file | Editing | Yes | Reference image; repeat the field for multiple uploads, up to 16 images, PNG / JPEG / WebP; single-image editing may also use one image field |
mask | file | Editing | No | Alpha PNG; transparent areas are redrawn and it applies to the first image; multipart only, forwarded unchanged |
output_format | string | Editing | No | Defaults to png, options are png / jpeg / webp; effective only on edits |
n | integer | Editing | No | Number of generated images; sent only on edits when n > 1, otherwise one image is returned |
Size details
size has two uses:
- Quick experimentation: send
1K/2K/4K, and sendaspectRatiofor text-to-image. - Specify the request canvas: send a
widthxheightvalue from the table. These are the specifications that the default providers reproduce reliably;aspectRatiois not also required.
The table below shows the sizes actually applied by the default providers. Explicit sizes outside the table are aligned by aspect ratio to the nearest supported specification. Some advanced providers may retain more sizes, but that behavior should not be treated as a cross-provider contract.
| Aspect ratio | 1K | 2K | 4K |
|---|---|---|---|
| 1:1 | 1280x1280 | 2048x2048 | 2880x2880 |
| 16:9 | 1280x720 | 2048x1152 | 3840x2160 |
| 9:16 | 720x1280 | 1152x2048 | 2160x3840 |
| 4:3 | 1280x960 | 2048x1536 | 3312x2480 |
| 3:4 | 960x1280 | 1536x2048 | 2480x3312 |
| 3:2 | 1280x848 | 2048x1360 | 3520x2336 |
| 2:3 | 848x1280 | 1360x2048 | 2336x3520 |
| 5:4 | 1280x1024 | 2048x1632 | 3216x2560 |
| 4:5 | 1024x1280 | 1632x2048 | 2560x3216 |
| 21:9 | 1280x544 | 2048x864 | 3840x1632 |
Explicit dimensions select the aspect ratio and tier, but the final returned pixels still depend on the actual provider. When a fixed delivery size is required, use a value from the table, pin a verified provider, and read the actual returned image pixels after generation. quality affects quality, latency, and billing, but does not change the requested aspect ratio.
Use a lowercase half-width x in size strings (for example, 1728x2304), not an uppercase X or full-width ×. For general semantics of advanced size and quality options, see the OpenAI Image Generation guide.
OpenAI compatibility
This interface is compatible with the OpenAI Images API. When migrating from OpenAI, note that the following parameters are not currently forwarded or supported by this gateway and are silently ignored when set:
output_compression: compresses the output image—unsupported by this gateway. To compress, usex-input-image-compresson edits to compress input reference images (a different use case; see above).background(opaque/transparent/auto): unsupported; gpt-image-2 outputs an opaque background by default.output_format: unsupported on the text-to-image endpoint (the upstream default PNG is always returned); effective only on edits.n: unsupported on the text-to-image endpoint (always one image); effective only on edits whenn > 1.- Caller-facing
stream/partial_images: unsupported; callers always receive one complete JSON response (see “Response” below).
Response
The response is always one complete JSON response, with no caller-facing streaming. The gateway and upstream may use internal streaming to avoid Cloudflare 524 timeouts, but this is transparent to callers, who receive only the complete JSON body.
Each image in data[] is returned as b64_json (raw base64) or url (a serve URL); usage provides usage information.
{
"created": 1717488000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA..."
}
],
"usage": {
"input_tokens": 256,
"output_tokens": 1568,
"total_tokens": 1824,
"generated_images": 1
}
}b64_jsonis a raw base64 string. Before saving it or displaying it in a frontend, prepend thedata:image/png;base64,prefix yourself.urlis a time-limited serve link; copy the image to your own storage promptly.usagecontainsinput_tokens(forwarded when reported by the upstream),output_tokens,total_tokens, andgenerated_images.
Organization-level forced URL output
Organization administrators can enable “Force image responses to use URLs” on the Images → Audit / Security Controls page in the console. Once enabled, all image generation and editing requests for that organization return only serve URLs and no longer return b64_json. The response body shrinks from several megabytes of base64 to one link, improving serialization and transfer speed:
- OpenAI interface:
data[].url(withoutb64_json). - Google interface:
fileData.fileUri(the URL-bearing field in a GeminiPart), rather thaninlineData. - ComfyUI asynchronous jobs: already return
outputs[].url; behavior is unchanged.
Serve files referenced by the URL have a time-to-live (TTL) and are removed by the archive retention policy; they are not permanent. When this option is enabled, copy images to your own storage as soon as possible after receiving the response instead of referencing the URL long term.
Pricing
Billing is per image based on image specification and quality tier. Actual prices are shown in the console, with organization-specific prices taking precedence.
Latency and error handling
Image generation and editing latency varies significantly with quality and resolution. Set the client timeout to at least 600 seconds:
auto(default): the model selects quality automatically based on content; latency falls within the ranges below.low: approximately 10–40s.medium: approximately 30–90s.highor complex 2K / 4K editing: 3–5 minutes; multi-image fusion takes longer, so reserve timeout according to the most complex scenario.
Integration guidance:
- Keep the API Key on the server and do not expose it in the browser.
- Limited retries are appropriate for transient network errors such as connection timeouts and 5xx jitter.
- When
urlis returned, copy the image to your own storage promptly because the link is time-limited.