Image generation
Generate, edit, and stream images through the Inference Cheap API.
Use https://openai.inference.cheap/v1 with a key that allows image generation.
Choose an interface
| Interface | Use it for |
|---|---|
POST /v1/images/generations | Generate images from a prompt. |
POST /v1/images/edits | Edit images, optionally with a mask. |
POST /v1/responses with an image_generation tool | Generate or edit images in a conversation. |
All three interfaces support streaming.
Models
Only GPT Image 2.5 is available for now. Set model to gpt-image-2.5 in
every request. Requests with another model, or without model, fail with
503 Service temporarily unavailable.
Generate an image
Install openai and set INFERENCE_CHEAP_API_KEY:
import base64
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
api_key=os.environ["INFERENCE_CHEAP_API_KEY"],
base_url="https://openai.inference.cheap/v1",
timeout=300.0,
max_retries=0, # Avoid duplicate generations.
)
result = client.images.generate(
model="gpt-image-2.5",
prompt="A small red sailboat on a calm blue lake, watercolor illustration.",
n=1,
output_format="png",
)
Path("sailboat.png").write_bytes(base64.b64decode(result.data[0].b64_json))Edit an image
Pass a local image file:
with open("sailboat.png", "rb") as source:
result = client.images.edit(
model="gpt-image-2.5",
image=source,
prompt="Change the sail to yellow. Keep the boat and lake composition.",
output_format="png",
)
Path("sailboat-edited.png").write_bytes(
base64.b64decode(result.data[0].b64_json)
)For JSON requests, use an HTTPS URL or a base64 data URL in images[].image_url.
Add a mask with mask.image_url:
{
"model": "gpt-image-2.5",
"prompt": "Change the sail to yellow.",
"images": [
{ "image_url": "data:image/png;base64,REPLACE_WITH_IMAGE_BASE64" }
]
}Multipart fields: image / image[], optional mask. file_id is unsupported.
Masks do not guarantee that areas outside the mask stay unchanged.
Parameters and output
The following parameters apply to /v1/images/generations and /v1/images/edits.
quality, style, and input_fidelity are not configurable and silently ignored.
| Parameter | Current behavior |
|---|---|
prompt | Required, non-empty. |
model | Required: gpt-image-2.5. See Models. |
n | Positive integer limiting returned images. Omit for all. The count is not guaranteed. All generated images are billed, including those not returned. |
size | Sets only the aspect ratio, from 1:3 to 3:1; other values are ignored. Images are always about 1.57 megapixels, so 1024x1024 returns 1254x1254. |
aspect_ratio | W:H, for example 16:9. Not an OpenAI parameter: in the SDK, pass it in extra_body. Overrides size. |
quality | Ignored. Always auto. |
style | Ignored. |
background | auto (default), opaque, or transparent. With auto, the model chooses from the prompt: an isolated object often comes back transparent. opaque always gives a solid background. transparent requires png or webp. |
output_format | png, jpeg, or webp. |
output_compression | Controls JPEG and WebP compression. |
moderation | Does not disable safety checks. |
stream | false returns a final JSON response; true returns SSE events. |
partial_images | Requests streamed previews, which are not guaranteed. |
response_format | b64_json by default. url returns inline data: URLs, not download links. |
input_fidelity | Ignored. |
Stream images
Set stream: true to receive SSE events.
Generation events include image_generation.partial_image and
image_generation.completed; edits use the image_edit prefix. Handle error
events; save only completed images.
Use the Responses image tool
Use a text model with the image_generation tool:
response = client.responses.create(
model="gpt-5.6-sol",
input="Draw a watercolor red sailboat on a calm blue lake.",
tools=[{"type": "image_generation", "model": "gpt-image-2.5"}],
tool_choice={"type": "image_generation"},
)
images = [
item for item in response.output
if item.type == "image_generation_call"
and item.status == "completed" and item.result
]
if response.status != "completed" or not images:
raise RuntimeError("The response did not contain a completed image.")
Path("sailboat.png").write_bytes(base64.b64decode(images[0].result))For edits, include an input image and set action: "edit" in the tool.
To add a mask, set input_image_mask: { image_url: "..." } in the tool.
With stream: true:
- Previews arrive as
response.image_generation_call.partial_imageinpartial_image_b64. - The completed
image_generation_call.resultcontains the final image. response.completedmarks the end. Previews are not guaranteed.
API reference: Images and Responses image tool.