Cancel a Format run: cancel_effect, no_op and what you still pay
POST cancel on a Format run is idempotent. cancel_effect says canceled or no_op. You pay for generation done before the cancel, and no webhook is sent.

Cancel a Format run with POST /v1/format-runs/{run_id}/cancel, using a key with formats:write. The call is idempotent and returns the current receipt either way. The cancel_effect field tells you what happened: canceled means this call stopped a run in progress, and no_op means the run had already finished before the call. You pay for the generation that completed before the cancel.
What each outcome means
Read cancel_effect first, then status and usage on the same receipt.
| Case | `cancel_effect` | Receipt `status` | Billing |
|---|---|---|---|
| Run still queued or processing | canceled | canceled | Generation already finished is billed |
| Run finished first | no_op | completed or failed | Unchanged |
| Repeat cancel on a canceled run | Same current receipt | canceled | Unchanged |
Two details that surprise people
The word is spelled canceled, with one l, in the status and in the code values. A string match on cancelled will never fire.
A canceled run never delivers a webhook. If your integration is webhook-only, cancel is the one path with no delivery, so take the state from the receipt the cancel call returns. Skipped runs also never deliver, but a skipped run is already terminal on the create response.
Using cancel with queues and costs
A bulk queue has no cancel endpoint. To stop a queue, cancel its children one by one with their run ids. The queue marks the item canceled and frees its slot, and the next queued item starts, so cancel the queued items you want to stop quickly, or accept that the window will pick up the next one.
cancelable on the receipt is true only while the run is queued or processing, so check it before you call. After the cancel, read usage.billable_amount_usd_micros for the generation spend counted against the run's cap and usage.debited_usd_micros for the wallet amount. A cancel does not refund generation that had already completed. To redo only part of a canceled run's work, a run that left artifacts and has a thread_id can be continued with previous_run_id.
A cancel helper
A reliable helper does four steps. It reads the receipt and checks cancelable. It posts to cancel_url. It reads cancel_effect from the answer and logs the value with the run id. It then reads usage and records the spend so the books match the wallet. Because the call is idempotent, the helper can retry after a timeout without a second effect.
Cancel is also the right tool when a run has plainly gone wrong: a bad brief that you see in the first receipt, or a duplicate you started by mistake. Do it quickly, since every minute of processing can add generation spend. Remember that skipped runs are different: on_active_run: "skip" records a skipped run without starting it, costs nothing, and has nothing to cancel.
Log request_id from the cancel response too. If a cancel seems not to have worked, for example the spend keeps rising, support asks for that value together with the run id.
Sources
Related posts
More in Formats
- Format run media URLs never expire and anyone can open them
Media from a Sume Format run lives at durable media.sume.com URLs that anyone with the link can open. What that means for per-customer access and retention.
- Format webhook: 10 s timeout, 10 attempts, about 3 h 5 min of retries
A slow Format webhook gets 10 tries. Without jitter, the last starts 11,010 s after the first; with 10 s timeouts the span is about 3 h 5 min. Code included.
- Format webhook outcome: ok, degraded or error, and what to do
The format.run.terminal webhook has three outcomes. Verify the sume-v1 signature, then branch: ok uses output, degraded uses artifacts, error is a failed run.
- Same idempotency key, new body: Sume Format run 409 vs 200 replay
Same Idempotency-Key and body on a Sume Format run gives 200 with idempotency_hit true. A changed body or attachments gives 409. Bulk replays stay 202.
Written by Sume