GPT Image 1 to GPT Image 2.5 on Sume: what changes in the output

Moving from GPT Image 1 to ChatGPT Image 2.5 on Sume changes the response (URL, not base64), default quality, size grid and failures.

6 min readSume
All posts

Moving from GPT Image 1 to ChatGPT Image 2.5 on Sume changes five things in your code: the response carries a URL in data[].url and not base64 in b64_json, the default quality is high, sizes follow a short-side grid, the 30-second wait can return a 202 job envelope, and failed jobs are not billed. Prompts and the ratio field carry over; the model id becomes openai/gpt-image-2.5.

OpenAI's deprecations page is where the shutdown date for GPT Image 1 is announced; check it for the date that applies to you. This post covers the migration itself and says nothing about quality differences between models.

The five changes

Each row below is a change a migrating integration will meet. The right column says what to do.

If you store results in a database, add a column for the model id and tier next to each image. When prices or defaults change, you can then explain a cost movement from the data and not from memory.

GPT Image 1 integration against Sume's ChatGPT Image 2.5, read 2026-10-07
AreaWhat changesWhat to do
Response bodydata[].url instead of b64_jsonDownload from the URL; do not decode base64
Default qualityhigh when quality is omittedSet quality explicitly
SizesAspect ratio plus the model's gridUse aspect_ratio or a valid image_size
Slow requests202 job envelope after 30 secondsPoll the job on 202
FailuresFailed jobs are not billedRetry without a refund workflow

The response shape

Sume mirrors generated media and returns a URL. Code that did base64.b64decode(item['b64_json']) needs to fetch the URL instead. Download soon after the call and store the file in your own bucket if you need it later, since a URL is a link to a hosted copy and not a promise of permanence.

import os, requests
r = requests.post("https://api.sume.com/v1/images",
    headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]},
    json={"model": "openai/gpt-image-2.5", "prompt": "A lighthouse at dusk",
          "aspect_ratio": "4:3", "quality": "medium"}, timeout=60)
body = r.json()
print(r.status_code)
if r.status_code == 200:
    img = requests.get(body["data"][0]["url"], timeout=60)
    open("out.png", "wb").write(img.content)

Quality and cost

The default is the surprise. With quality omitted on ChatGPT Image 2.5, Sume uses high, which is $0.0659 per 1024 square image; medium is $0.0165. A migrated job that never set quality can cost four times what you expect. Set it to the tier you actually used on GPT Image 1.

Cost is per image, shown as usage.cost in the response, and is the billed amount.

A migration order that works

Do the changes in this order. First, swap the model id behind a config flag and set quality to the tier you used before. Second, change the response handler to read the URL and handle 202. Third, replace any fixed pixel sizes with an aspect_ratio unless you need exact pixels. Fourth, run a small batch on both models and compare the usage.cost totals with the price you expect. Only then move traffic.

Keep the old path reachable until the shutdown date on OpenAI's deprecations page has passed and you are sure nothing depends on it. GPT Image 1 is not in Sume's image catalog, so on Sume the migration is a one-way change of id.

Sizes and the 202 case

ChatGPT Image 2.5 sizes are multiples of 16 on a short-side grid, so a custom image_size has to land on it; use aspect_ratio when you do not need an exact size. If a call takes longer than 30 seconds, you get a 202 job envelope. Treat 202 as a normal result and poll the job; a code path that only handles 200 will drop slow images.

Failed jobs are not billed, so a retry loop does not pay twice. Cap the retries anyway, and log the model id and quality with each result so a later cost review can group by them.

Finally, test with a few real prompts at the ratio you ship. Check that the file you download opens, that the dimensions match your layout, and that usage.cost agrees with the table in this post. Those three checks catch nearly every migration surprise.

One more habit helps with both. Log the model id, tier and billed cost with every finished job, then review the log weekly for a mismatch between the tier you meant and the cost you paid. A mismatch is the earliest sign of a missing field or an unintended default.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume