Sume /v1/images returns 200 or 202: branch on the status code
A slow 4K or xhigh image request on Sume returns 202 with a job envelope, not the image body. A Python client that handles 200, 202 and 502 correctly.

POST /v1/images waits up to 30 seconds. If the image is ready, you get 200 with data[].url. If it is not, you get 202 with a job envelope, and the image comes later from the job result endpoint. Branch on the status code, not on the shape of the body. Sizes and tiers that push you over the wait, such as 4K, high quality and large n, are the likely cause.
The three outcomes
The docs define the sync path as a route-level default of mode: "sync" and wait_timeout_seconds: 30. A terminal failure inside the wait comes back as 502 with the error envelope; the same code, message and next-action fields appear on the job status. A 202 is not an error.
| Status | Meaning | What to do |
|---|---|---|
| 200 | Image ready inside the wait | Read data[].url and usage.cost |
| 202 | Wait budget expired, or mode was async or webhook | Poll status_url, then fetch result_url |
| 502 | Generation failed inside the wait | Read error.code and next_action; failed jobs are not billed |
| 400 | Parameter the model does not list | Fix the request; do not retry unchanged |
A client that handles all three
This script posts a request, returns URLs on 200, polls on 202 with backoff, and raises on anything else. It never resubmits the paid request just because a local timeout fired.
import os
import time
import requests
BASE = "https://api.sume.com"
HEAD = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def generate(body):
r = requests.post(BASE + "/v1/images", headers=HEAD, json=body, timeout=45)
if r.status_code == 200:
return [d["url"] for d in r.json()["data"]]
if r.status_code != 202:
raise RuntimeError("status %s: %s" % (r.status_code, r.text[:300]))
env = r.json()["data"]
delay = 2
while True:
st = requests.get(env["status_url"], headers=HEAD, timeout=30).json()
if st["data"]["terminal"]:
break
time.sleep(delay)
delay = min(delay * 2, 20)
return requests.get(env["result_url"], headers=HEAD, timeout=30).json()
print(generate({"model": "openai/gpt-image-2.5", "quality": "xhigh",
"prompt": "studio photo of a red kettle", "resolution": "4K"}))What to tighten in production
The loop stops when data.terminal is true in the status response. After it stops, check data.sume_status: only completed has images, while failed and canceled do not, and /result returns 409 job_not_completed until the result is ready. The job result keeps the generic job shape, not the image body, so parse result according to the Jobs and results page.
If you prefer not to poll, send mode: "webhook" with a public HTTPS webhook_url and verify the signed event on your side.
Not a progress stream
mode: "subscribe" is an alias of sync, a single bounded wait. It is not a progress feed. For progress, submit with mode: "async" and read GET /v1/jobs/{id}/events.
Testing the branch
Exercise all three paths before launch:
200: a smalllowquality request.202: sendmode: "async"and confirm you follow the envelope.400: send a parameter the model does not list and confirm you do not retry.
Sources
Related posts
More in Developers
- image_size, aspect_ratio or size: which field wins on Sume
Sume's image API has three size fields. image_size beats aspect_ratio, size takes only a tier, and 4:5 is 1080x1350 portrait. Examples for GPT and Nano Banana.
- Image-to-video not starting on my photo: frame_images vs references
Your photo is a reference, not a first frame, when it goes in input_references. Use frame_images with first_frame on Sume /v1/videos to pin the opening shot.
- imagen-4.0-ultra-generate-001 ended Aug 17: the Sume images request
Google shut down three imagen-4.0 ids on Aug 17, 2026. A curl call to POST /v1/images that branches on 200 or 202, with an Idempotency-Key and a catalog check.
- Japanese speech to text API: Sume STT with language_code ja
Transcribe Japanese audio with Sume STT: send language_code ja, read word times, and test a sample first. $0.01 per audio minute, 10 minute jobs.
Written by Sume