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.

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.
| Signal | Where | Fraction of work? |
|---|---|---|
| queued, processing, completed | GET /v1/jobs/{id}/status | No |
| job.started, generation.submitted | GET /v1/jobs/{id}/events | No |
| Terminal event | Webhook or poll | No |
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
- Image quality defaults differ: OpenAI auto, Sume high, Ideogram medium
Omit quality and the tier differs: OpenAI defaults GPT Image 2.5 to auto, Sume to high, Ideogram 4.5 to medium, Image 1.0 to low. Pin it before you budget.
- image_size presets (landscape_16_9, square_hd): what Sume sends
Named image_size presets map to ratios on Ideogram, Grok, Imagen and Nano Banana, but pass through on GPT and FLUX. What auto means on each, checked in code.
- "image_size must be a named preset" 400 on Sume: how to fix it
Sending image_size as a bare number or an empty object returns a 400 invalid_request. The three accepted shapes, a tested error table, and a safe builder.
- Index-Echo bilingual SRT from a Chinese video to Sume cues
Index-Echo S2TT turns Chinese speech into timed bilingual subtitles in 60-second windows. Convert its SRT into Sume caption cues and burn the English line.
Written by Sume