Read a Sume job's events to time the wait before generation
Read GET /v1/jobs/:id/events, find generation.submitted, and compute how long a job sat between created, queued and started. A Python helper with tested math.

Call GET /v1/jobs/:id/events, find the generation.submitted event, and subtract timestamps. The gap between job.created and job.started is time your job spent in Sume's queue, and the gap between job.started and generation.submitted is the hand-off. Everything after generation.submitted is the generation itself. This tells you whether a slow job is waiting for a seat or rendering.
What an event contains
The OpenAPI spec defines each event with seven fields. The data object holds sanitized details; raw provider task ids, raw provider URLs, callback signatures, API key metadata and idempotency keys are left out on purpose.
| Field | Values or type |
|---|---|
| type | job.created, job.queued, job.started, generation.submitted, job.completed, job.failed, job.canceled, webhook.delivery |
| source | sume or webhook |
| status | info, pending, processing, succeeded, failed, canceled, retrying |
| created_at | date-time |
| id, message, data | string, string, object |
A script that prints the timeline
The helper below keeps the last event of each type and returns the gaps in seconds. It needs no third-party package. Set JOB_ID and SUME_API_KEY, then run it. The gaps function is pure, so you can test it with a hand-written list of events.
import json, os, urllib.request
from datetime import datetime
def gaps(events):
at = {e["type"]: datetime.fromisoformat(e["created_at"]) for e in events}
pairs = [("job.created", "job.queued"), ("job.queued", "job.started"),
("job.started", "generation.submitted")]
return {f"{a} -> {b}": (at[b] - at[a]).total_seconds()
for a, b in pairs if a in at and b in at}
if __name__ == "__main__":
job_id = os.environ["JOB_ID"]
req = urllib.request.Request(f"https://api.sume.com/v1/jobs/{job_id}/events",
headers={"x-api-key": os.environ["SUME_API_KEY"]})
with urllib.request.urlopen(req, timeout=30) as r:
events = json.load(r)["data"]["events"]
for e in events:
print(e["created_at"], e["type"], e["status"], e["message"])
print(gaps(events))Reading the numbers
Events are a debugging tool. For the normal path, poll the status endpoint and follow next_action, and use events only when a job looks wrong.
- A long job.created to job.started gap means the job waited for a processing seat. Check your plan's concurrency in the admission docs before you add more load.
- A short wait and a long run after generation.submitted means the render is the slow part. Waiting more or polling less is the right response.
- A webhook.delivery event with status retrying means your receiver is slow or returning a non-2xx. Fix the receiver before you blame the render.
- No generation.submitted event on a failed job means it failed before it reached generation, so read the error in the job record.
Where to put this in a pipeline
Run the events read once per job, after it reaches a terminal state, and store the gaps next to the job record. A week of those numbers shows whether your waits come from your own burst size or from render time. If the first gap grows when you submit in large bursts, submit smaller waves. The admission docs describe a wave_size_hint in the generation_limits snapshot that you can use as a starting size.
The event list is a read, so it counts toward your read budget, which is 40 times the write budget on every plan. One read per finished job is far below any limit.
Sources
Related posts
More in Developers
- Get a 30-second track from Music 1.0 when there is no duration field
Music 1.0 rejects duration and duration_seconds. Steer length in the prompt, for example 'a 30-second track' with timestamped sections; a generation is $0.125.
- GET /v1/jobs returns 404 for a job another key created: Sume's rules
A Sume API key reads only jobs its own member created. A reconciler on a different member's key gets 404 not_found for a real job. How to design for it.
- GLM 5.3 Flash JSON output vs Sume's strict output_schema rules
GLM-5.3-Flash supports JSON output. Sume's run output_schema is stricter: object root, additionalProperties false, all properties required. A schema that works.
- Go httptest for a Sume poll loop: assert next_poll_after_seconds
A 29-line Go test: httptest answers in_progress with next_poll_after_seconds 30 twice, then completed, and asserts the loop slept 30 seconds twice.
Written by Sume