Cancel a GPT Image 2.5 job: only possible before it starts
Sume's POST /v1/jobs/{id}/cancel works only before generation work starts. How to read cancelable, what the 409 means, and what a client timeout does not do.

You can cancel a GPT Image 2.5 job on Sume only while it has not started generating. POST /v1/jobs/{id}/cancel succeeds for a job that is still queued and returns 409 once any external generation task has begun, because Sume will not refund work already submitted. The job envelope tells you in advance: cancelable is true only before generation starts, and cancel_url is null afterwards.
So if you sent a wrong prompt and want the money back, speed matters, and a job that is already processing will finish and be billed. The details below come from the OpenAPI cancel description, the jobs docs and generation admission, read 2026-10-03.
When is a job still cancelable?
Sume's queue-first admission means a valid job can sit in queued while your workspace's generation concurrency is full. That waiting time is when cancel works. Concurrency is a plan limit, so a batch larger than your concurrency produces a tail of queued jobs you can still drop.
Cancel is also limited to the member whose key or Agent turn created the job; per the jobs docs, only that member can cancel it.
| Job state | cancelable | Cancel call result |
|---|---|---|
queued, generation not started | true | 200, status CANCELED |
processing, generation started | false (cancel_url null) | 409 job_generation_already_started |
completed, failed | false | 409 job_not_cancelable |
| Already canceled | - | 200, idempotency_hit: true |
How do I cancel from code?
Submit with mode: "async" so you always get the job envelope, keep the cancel_url, and call it only if cancelable was true on your last read. This Python runs against the real routes and prints the outcome.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}", "Content-Type": "application/json"}
def main():
r = requests.post("https://api.sume.com/v1/images", headers=H, timeout=60, json={
"model": "openai/gpt-image-2.5", "quality": "low", "mode": "async",
"image_size": "1024x1024", "prompt": "A lighthouse at night, long exposure"})
r.raise_for_status()
d = r.json()["data"]
print("job", d["job"]["id"], "cancelable", d["cancelable"])
if d["cancelable"] and d["cancel_url"]:
c = requests.post(d["cancel_url"], headers=H, timeout=30)
print(c.status_code, c.text[:200])
main()What does the 409 mean for my bill?
A 409 on cancel means the job is past the point where Sume can stop it. The job keeps running and, if it completes, is billed in full. Failed or canceled generations are not billed, which is why a successful cancel is the only way to avoid the charge on a job you no longer want.
Do not confuse cancel with giving up locally. The docs say a client-side timeout does not cancel the job: it keeps running and still bills, and you have only stopped watching.
What should I do instead of canceling?
If you missed the window, use the result anyway or limit the damage on the next run.
- Test prompts at
quality: "low"; a wrong low-quality job is a small loss. - Submit in small waves rather than all rows at once, so a bad prompt is caught while the rest are not yet submitted.
- Use an
Idempotency-Keyper operation so a retry after a network fault does not create a second paid job. - Check
queue_full: a 429 with that code means your queue is full, and finishing or canceling existing jobs frees room.
How do I check a job before cancelling?
Read GET /v1/jobs/{id}/status and look at cancelable and the sume_status field before you call cancel; the status response also carries terminal and next_poll_after_seconds. A job that has already reached a terminal state returns 409 on cancel, so reading first spares you a pointless call. The same read works for a job you submitted in a previous session, as long as you stored its id.
How does this fit a batch workflow?
In a CSV run, jobs beyond your concurrency wait as queued. If you notice a prompt mistake after submitting fifty rows, list your jobs, find the ones still cancelable and cancel those, then fix the prompt and resubmit with new idempotency keys. The ones already processing will complete and bill; plan to accept that cost.
This is another reason to submit in waves. A wave of ten that you can inspect before the next wave limits how many jobs sit in the cancel window with a bad prompt, and keeps the number of unavoidable charges small.
Sources
Related posts
More in Developers
- Chinese text to speech API: set language zh or it reads as English
Sume TTS only guesses Korean and Japanese when the language is missing. For Mandarin send language zh and pick a voice tagged zh, then test one line.
- allowManagedModsOnly in Claude Code: does hosted Sume MCP still load?
allowManagedModsOnly keeps users' own Claude Code mods from loading. What it leaves alone, how a policy mod reviews the rest, and the Sume MCP connection.
- Claude Code mod: stop paid Sume calls after N in a session
Write a Claude Code mod that counts paid Sume MCP calls with a tool.call hook, denies call N+1, and fails closed. Code, matcher, and what it cannot cap.
- Claude Code mod hook skipped and a paid Sume call still ran
A Claude Code mod hook that throws or times out is skipped, so the call runs anyway. Add .catch to fail closed, and know what a mod still cannot guarantee.
Written by Sume