Image API
Generating images over the API
Images go through the Responses endpoint: the mainline model reads your description and calls image generation as a tool, and the picture comes back as a Base64 result on a stream event. Same address and same key as a text call — no separate image service to wire up.
- 01
Build the request body
Four things matter: put image_generation in tools and name the image model; set tool_choice to the same type so it renders instead of replying in text; turn stream on, since image generation is far slower than text and streaming keeps events flowing and the connection alive; turn store off so the turn is not retained server-side. The image description goes into input as a user message, and instructions only states the job. The snippet below is bash — on Windows, jump to the Python example in the next step.
curl https://api.xylemnode.com/v1/responses \ -H "Authorization: Bearer sk-your-key" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-sol", "instructions": "Generate the requested image.", "input": [ { "role": "user", "content": "A ginger cat in a spacesuit standing on the moon, blue Earth in the distance, cinematic lighting, photorealistic." } ], "tools": [{ "type": "image_generation", "model": "gpt-image-2" }], "tool_choice": { "type": "image_generation" }, "stream": true, "store": false }' - 02
Pull the image out of the stream
The response is SSE: read the JSON after each data: line, keep only events whose type is response.output_item.done, and find the one whose item.type is image_generation_call — its item.result is the finished image in Base64. Decode it and write it to a file. Note that result is a long string, not a URL, so don't treat it as an image address or print it to your terminal.
import base64 import json import requests PROMPT = "A ginger cat in a spacesuit standing on the moon, blue Earth in the distance, cinematic lighting, photorealistic." payload = { "model": "gpt-5.6-sol", "instructions": "Generate the requested image.", "input": [{"role": "user", "content": PROMPT}], "tools": [{"type": "image_generation", "model": "gpt-image-2"}], "tool_choice": {"type": "image_generation"}, "stream": True, "store": False, } with requests.post( "https://api.xylemnode.com/v1/responses", headers={"Authorization": "Bearer sk-your-key"}, json=payload, stream=True, timeout=600, ) as response: response.raise_for_status() for raw in response.iter_lines(): if not raw: continue line = raw.decode("utf-8") if not line.startswith("data:"): continue chunk = line[5:].strip() if chunk == "[DONE]": break event = json.loads(chunk) if event.get("type") != "response.output_item.done": continue item = event.get("item") or {} if item.get("type") == "image_generation_call" and item.get("result"): with open("moon-cat.png", "wb") as file: file.write(base64.b64decode(item["result"])) print("saved moon-cat.png") - 03
Swap models, tune the output
Switch image models as needed: gpt-image-2.5-flare is faster, gpt-image-2.5-sunburst is more precise but slower — go by the model list in your console. Output options live on the same object inside tools: size sets the frame, quality the level of detail, background can request transparency (only png / webp support it) and output_format picks the file type. Add partial_images (1-3) and you'll receive a few preview drafts while it renders, as response.image_generation_call.partial_image events.
"tools": [{ "type": "image_generation", "model": "gpt-image-2.5-flare", "size": "1024x1536", "quality": "high", "background": "transparent", "output_format": "png", "partial_images": 2 }]
- Endpoint
https://api.xylemnode.com/v1/responses- Method
POST (Bearer auth)- Mainline model
gpt-5.6-sol- Tool
image_generation- Image model
gpt-image-2- Result field
image_generation_call.result (Base64)
Two things that trip people up
First, the mainline model only reads the description and triggers the tool, so it has to be one that supports image_generation. If you get a tool-unavailable error, pick another mainline model from your console list. Second, one request produces one finished image. To keep editing the same image, turn store on and point previous_response_id at the earlier response on the next call — with store off the turn isn't retained, so there is nothing to continue from.