A Sume job failed: read GET /v1/jobs/:id/events, then act

The events endpoint is the first stop for a failed or canceled Sume job: the eight event names, what stays hidden, error categories, and a TypeScript reader.

5 min readSume
All posts

When a Sume job ends failed or canceled, read GET /v1/jobs/:id/events before you do anything else. It returns the job's public timeline, and the job record holds the public error with its category, stage, retryability, and next action. GET /v1/jobs/:id/result is no use for these jobs, since it answers 409 job_not_completed.

Events are a pull snapshot, not a stream. There is no SSE or WebSocket on the Developer API today, so you read the endpoint when you need it, such as after a terminal status.

The event names

Eight event types appear in the public timeline, from the Jobs and results page.

Public job event types, as of 2026-10-09 (Jobs and results).
EventRead it as
job.createdSume has a durable job id
job.queuedWaiting for a concurrency slot
job.startedA worker picked it up
generation.submittedGeneration work was submitted
job.completedResult ready
job.failedTerminal failure with a public error
job.canceledCancel was accepted before generation started
webhook.deliveryA callback attempt for the job

Read the timeline

The snippet prints the raw JSON, since the point is to look at the events and the request_id. Public events never show raw provider task ids or raw provider URLs, so there is nothing sensitive to scrub, but the docs still ask you not to paste API keys or signed URLs into tickets.

const jobId = process.argv[2];
const res = await fetch(`https://api.sume.com/v1/jobs/${jobId}/events`, {
  headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
});
if (!res.ok) throw new Error(`events read failed: ${res.status}`);
console.log(JSON.stringify(await res.json(), null, 2));

Pick the next action by error category

The Errors page lists the common job error categories and the usual response. These are the ones that tell you whether to retry.

  • validation: correct the input. Retrying the same body will fail the same way.
  • quota: add funds or lower the request cost.
  • queue, generation_unavailable, runtime_unavailable: retry later, with the same idempotency key, and do not retry aggressively.
  • generation_rejected: check the events and fix the unsupported input.
  • generation_timeout and worker_timeout: poll the status, or retry later.
  • internal: contact support with the request or job id.

Reading the sequence

A healthy job shows job.created, job.queued, job.started, generation.submitted, and then job.completed. A job that failed before generation starts would have no generation.submitted entry, which points to a failure before generation work was submitted. A job with generation.submitted and then job.failed failed during generation, and by then cancel was no longer possible (409 job_generation_already_started). A webhook.delivery entry after the terminal event is the delivery attempt, not a new job state.

What to keep

Store the job id, the request_id, and the events you read at failure time. Sume refunds the reservation of a failed job where applicable, so the billing question is separate from the retry question. If you decide to retry, reuse the idempotency key only for an exact retry of the same payload. A changed payload needs a new key, or you will see 409 idempotency_conflict.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume