Image job progress bar: Sume has no percentage, so show job stages

ChatGPT Images 2.5 shows a progress percentage. Sume image jobs report queued, processing and completed plus events, and stream:true returns 400.

4 min readSume
All posts

A user in OpenAI's Images 2.5 announcement thread notes that in instant mode there is now a progress percentage you can watch (OpenAI Developer Community, read 2026-10-04). People will ask your app for the same. On Sume that exact bar cannot be built, but an honest stage bar can.

What Sume reports

The Image API docs say Sume does not serve native streaming yet: every catalog row reports supports_streaming: false and stream: true returns 400 streaming_not_supported. The documented path is mode: "async", then GET /v1/jobs/:id/events for progress, or a webhook for the terminal event. The jobs docs list job statuses (queued, processing, completed, failed, canceled) and events such as job.created, job.queued, job.started, generation.submitted, job.completed and job.failed. None of these carries a percentage.

Progress signals for an image job, Sume docs, read 2026-10-04
SignalWhereFraction of work?
queued, processing, completedGET /v1/jobs/{id}/statusNo
job.started, generation.submittedGET /v1/jobs/{id}/eventsNo
Terminal eventWebhook or pollNo

Build the bar from stages

Map the stages to labelled steps: Accepted, Waiting for a slot, Generating, Done. Do not draw a smooth bar that implies a fraction you do not have. Slow settings (4K, high quality, large n) are the likeliest to move from a 200 to a 202 job envelope, so build the async branch first.

Submit async and poll

Use exponential backoff in production and stop on a terminal status, as the docs advise. Do not resubmit the paid request only because your own poll timed out.

import os
import time
import requests

h = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
body = {"model": "openai/gpt-image-2.5", "prompt": "a poster of a red kite", "mode": "async"}
r = requests.post("https://api.sume.com/v1/images", headers=h, json=body, timeout=30)
status_url = r.json()["data"]["status_url"]
for _ in range(40):
    text = requests.get(status_url, headers=h, timeout=30).text
    print(text[:200])
    if any(s in text for s in ("completed", "failed", "canceled")):
        break
    time.sleep(3)

Sources

Related posts

More in Developers

All Developers posts

Written by Sume