Language
Inference Space Docs

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 model to gpt-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 to ai.inf.space).
  • The console and API share https://ai.inf.space; use the /v1 path shown in each curl / SDK example.
  • Authentication header: Authorization: Bearer $TOS_API_KEY, where the Key starts with gk_.

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 (default png, options png / 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 when n > 1; when omitted or set to 1, one image is returned. Text-to-image does not support n and 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.

ParameterTypeApplicable interfaceRequiredDescription
modelstringGeneralYesCurrently gpt-image-2 is the primary model
promptstringGeneralYesGeneration or editing instruction; Chinese is supported natively
sizestringGeneralNoTarget size; see the size details below
qualitystringGeneralNoDefaults to auto; options are auto / low / medium / high, affecting quality and billing tier
aspectRatiostringText-to-imageNoGateway extension, such as "3:4", automatically aligned to a supported widthxheight at the selected size tier
providerstringText-to-imageNoGateway extension for overriding the provider selection
image[]fileEditingYesReference image; repeat the field for multiple uploads, up to 16 images, PNG / JPEG / WebP; single-image editing may also use one image field
maskfileEditingNoAlpha PNG; transparent areas are redrawn and it applies to the first image; multipart only, forwarded unchanged
output_formatstringEditingNoDefaults to png, options are png / jpeg / webp; effective only on edits
nintegerEditingNoNumber of generated images; sent only on edits when n > 1, otherwise one image is returned

Size details

size has two uses:

  1. Quick experimentation: send 1K / 2K / 4K, and send aspectRatio for text-to-image.
  2. Specify the request canvas: send a widthxheight value from the table. These are the specifications that the default providers reproduce reliably; aspectRatio is 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 ratio1K2K4K
1:11280x12802048x20482880x2880
16:91280x7202048x11523840x2160
9:16720x12801152x20482160x3840
4:31280x9602048x15363312x2480
3:4960x12801536x20482480x3312
3:21280x8482048x13603520x2336
2:3848x12801360x20482336x3520
5:41280x10242048x16323216x2560
4:51024x12801632x20482560x3216
21:91280x5442048x8643840x1632

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, use x-input-image-compress on 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 when n > 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_json is a raw base64 string. Before saving it or displaying it in a frontend, prepend the data:image/png;base64, prefix yourself.
  • url is a time-limited serve link; copy the image to your own storage promptly.
  • usage contains input_tokens (forwarded when reported by the upstream), output_tokens, total_tokens, and generated_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 (without b64_json).
  • Google interface: fileData.fileUri (the URL-bearing field in a Gemini Part), rather than inlineData.
  • 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.
  • high or 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 url is returned, copy the image to your own storage promptly because the link is time-limited.

On this page