Image API wait_timeout_seconds: submit now, poll later

Set wait_timeout_seconds to 0 on POST /v1/images to stop blocking and treat every call as a job. How the 200 and 202 answers differ and a polling script.

4 min readSume
All posts

wait_timeout_seconds on POST /v1/images takes 0 to 30 and defaults to 30. It is the blocking wait budget, so a low value makes the call return sooner with a 202 job envelope you poll yourself. Always branch on the status code, because a quick model can still answer 200 inside any budget above zero.

The Image API docs list the field in the request table: wait_timeout_seconds, integer, 0 to 30, default 30 on this route, "blocking wait budget for sync / subscribe." The same table says the default mode is sync.

When is a short wait the right choice?

A web request handler that must answer in a few seconds should not hold a connection for 30. A queue worker that fans out fifty images does not want fifty open connections either. In both cases, ask for little or no waiting and collect results later.

Choosing a value is simple. Use 0 when you will never wait. Use a small number such as 5 if you want fast models to answer inline while slow ones fall back to a job. Leave the default of 30 when a person is waiting and a delay under half a minute is acceptable.

  • Serverless handlers with short execution limits.
  • Fan-out scripts that submit many images then read them together.
  • Anything that already stores job ids for crash recovery.

What do the three answers look like?

The shapes come from the docs. Do not parse the body to work out which one you got.

POST /v1/images outcomes (read 2026-10-02)
StatusMeaningWhat to do
200Image finished inside the wait budgetRead data[].url and usage.cost
202Job accepted, still runningPoll status_url, then read result_url
429 with queue_full or rate_limitedCapacity or request rateBack off using retry-after, reuse the idempotency key

A submit-then-collect script

This sends five prompts with a zero wait, keeps the job ids, then polls them. It tolerates the occasional 200. Set SUME_IMAGE_MODEL to an id from the catalog.

import os, time, requests
B = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def done(o):
    if isinstance(o, dict):
        if o.get("status") in ("completed", "failed", "canceled"): return True
        return any(done(v) for v in o.values())
    return False
pending, urls = [], []
for i in range(5):
    r = requests.post(B + "/v1/images", headers=H, timeout=30, json={
        "model": os.environ["SUME_IMAGE_MODEL"], "wait_timeout_seconds": 0,
        "prompt": f"Flat-lay product photo, variant {i + 1}"})
    if r.status_code == 200: urls += [d["url"] for d in r.json()["data"]]
    elif r.status_code == 202: pending.append(r.json()["data"])
    else: print(r.status_code, r.text[:200])
for d in pending:
    while not done(requests.get(d["status_url"], headers=H).json()): time.sleep(3)
    print(requests.get(d["result_url"], headers=H).json())
print(urls)

What stays the same?

Billing does not change with the wait budget. A completed image is billed in full and a failed or cancelled one is not. Closing your connection early is not a way to cancel: the Sume docs say client disconnects are treated as failed generations for billing, and a related post covers what happens to the job.

For many images, a webhook is cleaner than polling. Send mode: "webhook" with a public HTTPS webhook_url and verify the x-sume-webhook-signature header as the webhooks guide describes.

Keep the job ids you collect. The Jobs docs say to store the id from submit responses so you can recover work after a process restart, and to avoid resubmitting a paid request just because a local process timed out. A zero wait makes that discipline the norm instead of the exception.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume