GPT Image 2.5 API in Python: a working example
Call the GPT Image 2.5 API from Python and JavaScript, poll the task for image URLs, edit with references, and fix model ID and parameter errors.
Read as MarkdownTo call the GPT Image 2.5 API, send a POST to https://api.seedrouter.ai/v1/images/generations with a model ID such as gpt-image-2.5-flare and a prompt, keep the task id from the response, and poll GET /v1/tasks/{id} until the status is completed. The finished task holds URLs to your images. The same endpoint handles text-to-image, reference edits and masked edits.
This guide is a complete, runnable path in Python, with the JavaScript equivalent, followed by the errors people hit most often and what each one means.
What do you need before the first request?
Two things: an API key and a model ID.
Create a key in API keys and keep it in an environment variable on your server, never in browser code:
export SEEDROUTER_API_KEY="your-key"Then choose one of the four GPT Image 2.5 model IDs. Copy them exactly; there is no bare gpt-image-2.5 ID.
| Model ID | Model | Billing |
|---|---|---|
gpt-image-2.5-flare | Flare | Flat price per image |
gpt-image-2.5-sunburst | Sunburst | Flat price per image |
gpt-image-2.5-flare-official | Flare | Token usage |
gpt-image-2.5-sunburst-official | Sunburst | Token usage |
If you are unsure which model to start with, use Flare; Flare vs Sunburst explains when Sunburst is worth it.
How do you generate an image with Python?
Submitting returns immediately. The response is a task reference, not the image.
import os
import requests
response = requests.post(
"https://api.seedrouter.ai/v1/images/generations",
headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
json={
"model": "gpt-image-2.5-flare",
"prompt": "An amber glass bottle on a cream background, studio lighting",
"size": "1024x1024",
"quality": "low",
},
timeout=60,
)
response.raise_for_status()
task_id = response.json()["id"]Save task_id before doing anything else. It is the only handle on the work you just paid for, and it is how you recover if your process restarts while the image renders.
How do you get the image back?
Poll the task every few seconds until it finishes. This loop waits up to ten minutes; reaching that deadline stops your loop, not the task.
import time
print(f"Task ID: {task_id}")
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
result = requests.get(
f"https://api.seedrouter.ai/v1/tasks/{task_id}",
headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
timeout=30,
)
result.raise_for_status()
task = result.json()
if task["status"] == "completed":
for image in task["output"]["data"]:
print(image["url"])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(3)
else:
raise TimeoutError(f"Still waiting. Resume polling task {task_id}.")Download the URLs you want to keep and store them yourself. Result URLs are a delivery handoff, not long-term storage.
What does the same call look like in JavaScript?
The request is identical; only the HTTP client changes. Run it on your server so the key never reaches a browser.
const response = await fetch('https://api.seedrouter.ai/v1/images/generations', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SEEDROUTER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-image-2.5-flare',
prompt: 'An amber glass bottle on a cream background, studio lighting',
size: '1024x1024',
quality: 'low',
}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const { id: taskId } = await response.json();Poll GET https://api.seedrouter.ai/v1/tasks/${taskId} with the same header, exactly as in the Python loop.
How do you edit an existing image?
Add reference images to the same request. There is no separate edit endpoint and no mode field: sending images makes it an edit, and adding a mask limits the change to one region.
{
"model": "gpt-image-2.5-sunburst",
"prompt": "Make the bottle blue. Preserve the composition and lighting.",
"images": [{"image_url": "https://example.com/reference.png"}],
"mask": {"image_url": "https://example.com/mask.png"}
}Inputs must be public HTTPS URLs. You can send up to 16 reference images as PNG, JPEG or WebP under 50 MB each. The mask is a PNG under 4 MB, the same size as the first reference image, and its transparent area marks what to change. Base64 strings, data: URLs and file uploads are rejected, so upload files to your own storage first and send the URLs.
Why does the API say the model is not available?
Error code 20002 with HTTP 400 ("The requested model is not available.") means the model value is not an ID the API serves. The usual cause is a near miss: gpt-image-2.5 without a tier, gpt-image-2-5-flare with a dash instead of the dot, or a typo in sunburst. Copy an ID from the table above.
Parameter errors are reported before the model is checked. If a request also has an invalid field, you get 20001 with a message that names the field, for example quality. Fix that first; the model error appears on the next attempt if the ID is still wrong.
| Error code | HTTP | What to do |
|---|---|---|
20001 | 400 | Fix the field named in the message |
20002 | 400 | Use one of the four model IDs exactly |
10001 | 401 | Check the Authorization header |
A task can also fail after it was accepted. That query still returns HTTP 200, with status: "failed" and an error object such as code 60001 (content policy) or 60002 (generation failed). Failed tasks are not charged. The error catalog lists every code, including balance and rate-limit errors, with the next step for each.
Frequently asked questions
Is there an official Python SDK call that returns the image directly?
Not on this API. Delivery is asynchronous: you always submit, keep the task ID, and poll. stream and partial_images are not supported.
Can I request several images at once?
Yes. Set n from 1 to 10. The finished task lists one URL per delivered image, and you are billed for the images delivered.
How do I get a transparent PNG?
Set background to transparent and output_format to png. JPEG has no alpha channel, so that combination is rejected before it runs.
Ship the integration around the task ID
Store the task ID the moment you receive it, poll with a deadline, and treat a polling timeout as "still running" rather than "failed." Everything else, including every field and limit, is in the GPT Image 2.5 API reference, and you can try a request without code in the Playground.



