Read a completed Sume /v1/videos poll response, field by field
What id, generation_id, polling_url, status, unsigned_urls and usage.cost mean on a finished Sume video job, and which to store.

A completed poll on GET /v1/videos/{jobId} returns a small object, and every field in it has one job: id and generation_id identify the job, polling_url is where you asked, status says completed, unsigned_urls is where the file lives, and usage.cost is what the workspace was billed. Store id and unsigned_urls[0], read usage.cost for your own books, and treat the rest as confirmation.
The sample in the Sume docs is short enough to read in one pass, so this note walks it line by line and then lists what a client should persist. It is for anyone writing the first poll loop, or reviewing one that only checks status.
The fields on a completed job
The docs' completed example carries id, generation_id, polling_url, status, model, unsigned_urls and usage. In that example id and generation_id are the same value, which is why one stored id is enough to resume; the docs do not promise they are always equal for every route, so keep both if you log both.
| Field | What it holds | What to do with it |
|---|---|---|
| id | The job id returned at submit | Store it; it is the key for every later read |
| generation_id | A second identifier for the same generation | Log it next to id |
| polling_url | The URL you poll | Reuse it instead of rebuilding the path |
| status | pending, in_progress, completed, failed or cancelled | Stop polling on the last three |
| model | The model id, or sume/auto if you sent Auto | Do not infer the family from the output |
| unsigned_urls | Array of content URLs, index 0 first | Download with your API key header |
| usage.cost | The Sume billable amount in USD | Record it per job |
unsigned_urls are not public links
The name is easy to misread. An unsigned URL carries no signature, so it is not a shareable link: the docs show downloading the file from the content endpoint with an Authorization: Bearer header, for example GET /v1/videos/{jobId}/content?index=0. Fetch it from your server and put the bytes where your own users can reach them.
The model echo matters for Auto. A request sent with model: "sume/auto" reports sume/auto on the poll, and Sume does not disclose which family served it. Do not build logic on traits of the output to guess the model.
usage.cost is the billable amount
In the Sume differences table, billing is a workspace USD balance reserved on submit at provider list times 1.25, and usage.cost is the Sume billable amount. That is the number to reconcile against your balance; it is not the vendor price. The docs example shows a cost of 0.25 purely as a sample, so do not read it as a rate.
What a client should persist
Everything else on the page can be re-read from the job at any time. What the docs do not state is how long a job stays readable, so copy the file out when the job completes rather than assuming it stays fetchable.
- The job
idthe moment submit returns, before the first poll. - The final
statusand, on failure, theerrorfield the docs tell you to check. unsigned_urls[0], or the content endpoint path, plus theindexyou used.usage.cost, so a finance export does not need a second API call.
A short parsing example
In practice the parser is three lines: check status against the three terminal values, take unsigned_urls[0], and read usage.cost. Everything else is context. If you also want a single place to keep an audit trail, log id, generation_id, model and usage.cost together as one JSON line per finished job, and your reconciliation with the workspace balance becomes a sum over that file.
When a job fails, the same object carries an error field instead of URLs. The docs tell you to check it, and to confirm that any reference images were public HTTPS links in a supported format. Treat a missing unsigned_urls on a completed job as a bug to report, with the job id and request id, not as something to retry.
Sources
Related posts
More in Developers
- Read capabilities from the Video Router models list before you pin
GET /v1/video-router/models returns capabilities per model. Why the docs say to read them instead of assuming one envelope, and what differs by model.
- Read job events for a stuck narration take: a snapshot, not a stream
GET /v1/jobs/:id/events lists job.created, queued, started, generation.submitted and the terminal event. A pull snapshot for debugging a TTS or music take.
- Debug a slow Sume job with GET /v1/jobs/:id/events
A slow Sume job is queued, running, or waiting on your webhook. The events timeline separates them: job.queued, job.started, terminal, webhook.delivery.
- Read the TTS Router catalog in Python: price per 1M from list micros
Sume's TTS Router catalog publishes list micro-dollars per character; billing is list x 1.25. A Python script prints price per 1M and per 1,000 characters.
Written by Sume