Image API returned 202 at 4K: handle the job envelope in Python

A slow 4K, high-quality or large-n request can miss the 30 second wait and return 202 with a job, not images. Branch on the status code, then poll.

5 min readSume
All posts

POST /v1/images waits up to 30 seconds and returns 200 with images if the job finishes in that time; otherwise it returns 202 with the standard job envelope. The docs name the slow cases: 4K output, high quality and a large n. Your code must branch on the status code, because the 202 body has no data[].url.

What each status means

A failed job inside the wait is a 502 with an error envelope, not a 202. Failed or cancelled generations use no credits.

Sume Image API docs and repo, read 2026-10-13
StatusMeaningNext step
200Images are ready in data[]Use data[].url
202Job accepted, not finishedPoll status_url, then read result_url
502Job failed inside the waitRead error.code and next_action
400Parameter the model does not listFix the request; no job was created

A handler that works for all outcomes

The function below returns the image list on 200 and polls the job on 202. It stops on the terminal flag that the status endpoint returns and only fetches the result when the job is completed. Client-side timeouts do not cancel the job, so store the job id if you give up.

Call it with generate({"model": "google/nano-banana-2.1", "prompt": "city skyline", "resolution": "4K"}).

import os, time, requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
BASE = "https://api.sume.com"

def unwrap(body):
    return body.get("data", body)

def generate(payload):
    r = requests.post(f"{BASE}/v1/images", headers=H, json=payload, timeout=60)
    if r.status_code == 200:
        return r.json()["data"]
    if r.status_code != 202:
        raise RuntimeError(f"{r.status_code} {r.text}")
    job = unwrap(r.json())
    while True:
        s = unwrap(requests.get(job["status_url"], headers=H, timeout=30).json())
        if s.get("terminal"):
            break
        time.sleep(s.get("next_poll_after_seconds") or 3)
    if s.get("sume_status") != "completed":
        raise RuntimeError(f"job ended as {s.get('sume_status')}")
    return requests.get(job["result_url"], headers=H, timeout=30).json()

Avoid the wait

If you already know a request is heavy, send mode: "async" and skip the 30 second hold. Use a webhook if you do not want to poll. Do not resubmit a paid request because your own timer fired.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume