Does a canceled Sume job send a webhook? Jobs do, runs do not
A canceled generation job delivers job.canceled with status ERROR, but a canceled or skipped Format, Action or Agent run sends no webhook. Handle both paths.

It depends on which surface you called. A generation job (POST /v1/models/... or a model route such as /v1/avatar-1.0/generate) sends job.canceled when it reaches the canceled state. A Format, Action or Agent Completion run never sends a webhook when canceled or skipped; its terminal event only fires on completed or failed. If your integration is webhook-only, run cancellation is the one path where nothing arrives.
Source pages: Webhooks, Run webhooks and Jobs and results, read 2026-10-02.
Which events does each surface send?
Both surfaces sign deliveries with the same sume-v1 scheme, so one verifier covers both. The event sets do not overlap.
| Surface | Events | Canceled | Skipped |
|---|---|---|---|
| Generation job | job.completed, job.failed, job.canceled | Delivers job.canceled with status ERROR and an error object | Not applicable |
| Format run | format.run.terminal | No webhook | No webhook |
| Action run | action.run.terminal | No webhook | No webhook |
| Agent Completion run | agent.run.terminal | No webhook | No webhook |
When can a job be canceled at all?
Cancellation succeeds only before generation work starts. Once generation has started, the API returns 409 job_generation_already_started with details.cancelable: false, and the job runs to completion. So job.canceled realistically follows a cancel of a job that was still queued. Canceling a job that is already canceled is idempotent and returns the same canceled job.
Runs behave differently. POST .../cancel on a run returns the current receipt either way, and cancel_effect says canceled when this call stopped a run in flight or no_op when it had already finished. Generation the run completed before the cancel is still billed.
How do I write a handler that does not hang on cancel?
Route on the event field, and treat a run you canceled as resolved the moment the cancel call returns. Do not leave a pending record waiting for a POST that cannot come. After you call cancel on a run, trust the cancel response, or poll status_url until payload.status is canceled.
For jobs, branch on all three events. job.failed and job.canceled both carry status: "ERROR" and an error object, so read the event name, not just the status, if you need to tell a failure from a cancel.
function handle(event: { event: string; job_id?: string; run_id?: string }) {
switch (event.event) {
case "job.completed":
return markDone(event.job_id!);
case "job.failed":
case "job.canceled":
return markEnded(event.job_id!, event.event);
case "format.run.terminal":
return markRun(event.run_id!); // never sent for canceled or skipped
default:
return; // unknown event: answer 204, not 500
}
}What about skipped runs?
A skipped run is recorded terminal immediately, without ever starting work, so there is no completion to announce. The create response already told you. Format defaults to on_active_run: "allow" while Action defaults to skip, so Action integrations meet this more often. Read status on the create response instead of waiting.
Net rule: for jobs, expect three events; for runs, expect one event for success or failure and use the API response for cancel and skip.
Sources
Related posts
More in Developers
- Sume job error category quota or queue vs 402 and 429
A Sume job error category quota means add funds or lower cost; queue means retry with the same key. They sit on the job, apart from 402 and 429 at submit.
- Sume job failed with worker_timeout: poll again or retry?
A Sume job error in the worker_timeout or generation_timeout category means poll status or retry later. runtime_unavailable means retry later, gently.
- Sume job metadata on Kling motion control and H3 Max lip sync
Both Kling 3.0 Motion Control and MiniMax H3 Max Lip Sync accept a metadata object stored with the Sume job request. It is not sent to the provider.
- Sume webhook retry schedule: jobs every 30 s, runs exponential
Sume job webhooks retry up to 10 times about 30 seconds apart; run webhooks back off exponentially to one hour. What each gives your endpoint to recover.
Written by Sume