Image request timed out: do you pay for it on Sume?
Sume bills image jobs by outcome. A client timeout does not cancel the job, so a finished image can still bill. Use async mode and poll; do not resubmit.

If your own client times out on a Sume image call, do not assume you are not charged. The Jobs docs say a client-side timeout does not cancel the job: it keeps running and still bills, and you have only stopped watching. The Image API docs also say generation billing is all-or-nothing, and that a failed or cancelled generation is not billed. So the outcome of the job decides the bill, not the state of your connection. Do not resubmit; look the job up.
What each page says
The two pages read differently at first glance, so here they are side by side.
| Page | Statement |
|---|---|
| Image API | Completed generations are fully billed; failed or cancelled generations are not billed. |
| Image API | Client disconnects: requests ending early are billed as failed generations (not at all). |
| Jobs and results | A client-side timeout does not cancel the job. The job keeps running and still bills. |
| Jobs and results | Not terminal? Poll. Do not resubmit. |
How to read them together
The Image API line covers a request that ends before generation completes, which is then a failed generation. The Jobs line covers the case where the job continues after you stop watching, which can finish and bill. Because you cannot tell from your side which happened, treat the job record as the source of truth.
Do this instead
Submit with mode: "async" and an Idempotency-Key, then poll the job status until it is terminal.
import os, time, uuid, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
sub = requests.post("https://api.sume.com/v1/images", timeout=60,
headers={**H, "Idempotency-Key": str(uuid.uuid4())},
json={"model": "openai/gpt-image-2.5", "prompt": "a red kite", "mode": "async"})
job_id = sub.json()["job"]["id"]
while True:
s = requests.get(f"https://api.sume.com/v1/jobs/{job_id}/status", headers=H, timeout=30).json()
if s["terminal"]:
break
time.sleep(s.get("next_poll_after_seconds") or 3)
print(s["sume_status"])Check your spend
GET /v1/usage can be filtered by job id to confirm what a job cost. Send Idempotency-Key on submits you retry, so a retry does not create a second job.
Sources
Related posts
More in Developers
- Sume images API n=5 returns 400 though the docs say up to 10
The Image API docs say n up to 10, but the catalog range is 1 to 4 for most models, 1 for Grok and 1 or 4 for Soul. The error text and a loop that batches.
- 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.
- Instagram Login or Facebook Login for a Reels publishing app?
Both logins can publish Reels. They differ in host, token and scopes, and resumable upload plus some metrics are Facebook Login only. Pick before you build.
- Instagram API Reels total_interactions: how it is calculated
Instagram's insights reference defines total_interactions as likes, saves, comments and shares minus unlikes and deletions, and marks it in development.
Written by Sume