Which ID to store from a Sume call: id, generation_id or request_id
Sume returns an id, a generation_id, a request_id and an error request_id. Store the job id and keep the req_ error id in logs only. Here is where each appears.

Store the job id, one string for every job. On the job routes it is returned as request_id, on the OpenRouter-compatible /v1/videos routes it is returned as id and repeated as generation_id, and on a webhook it is job_id. They are the same value, so one column named job_id covers every path. The only id you should not store as the job key is the req_... value inside an error envelope: it names a failed request, not a job.
The shapes come from Jobs and results, the video models reference and Errors and credits.
Where each id appears
| Field | Where | What it identifies | Store it as |
|---|---|---|---|
| request_id | Job submit response (async) | The job id | job_id |
| id | POST and GET on /v1/videos | The job id | job_id |
| generation_id | GET /v1/videos/{id} poll body | The job id again | Nothing extra |
| job_id | Webhook payload | The job id | job_id, also the dedupe key |
| error.request_id | Error envelope, shaped req_... | One failed request | Log field only |
One function that picks the right id
The Python below normalizes all three success shapes into one id and keeps the error id apart. Run it as is: it uses canned payloads, so no key is needed.
import asyncio
def job_id_of(payload: dict) -> str | None:
"""Return the job id from a submit, poll or webhook body."""
body = payload.get("data", payload)
for key in ("job_id", "id", "generation_id", "request_id"):
value = body.get(key)
if isinstance(value, str) and value and not value.startswith("req_"):
return value
return None
def error_id_of(payload: dict) -> str | None:
return (payload.get("error") or {}).get("request_id")
async def main() -> None:
samples = [
{"request_id": "job_123", "status_url": "/v1/jobs/job_123/status"},
{"id": "job_01HXYZ", "generation_id": "job_01HXYZ"},
{"event": "job.completed", "job_id": "job_456"},
{"error": {"code": "rate_limited", "request_id": "req_abc"}},
]
for s in samples:
print(job_id_of(s), error_id_of(s))
asyncio.run(main())Why the job id is the one that matters
The job id is the key for everything that follows submit: the status route, the result route, a cancel, the event log and the webhook redeliver call all take it. If your process dies between a paid submit and a database write, that id is the only handle you have, so write it in the same step as the submit. If it is lost, you cannot recover the job and a resubmit will bill again.
On /v1/videos, a replay with the same Idempotency-Key returns the original job, so the key you generate is a second route back to the same id. Persist the key before you send the request.
Caveats
- An error envelope has
error.code,error.messageanderror.request_id. Quote thereq_...id in a support ticket, but do not use it to poll anything. - A
409 idempotency_conflictmeans the key was reused with a different body. Generate a new key for new work. - Submit-time failures such as
402 insufficient_creditsreturn no job, so there is nothing to store and nothing to poll.
Sources
Related posts
More in Developers
- Which Lyria ran? job.model vs job.request.routed_model on Sume
On Sume's Music Router, job.model echoes what you sent and job.request.routed_model names the engine that ran. How to read both and pin a Lyria id.
- Sume rate limit scope: /v1 and MCP count, OPTIONS preflights do not
The Sume limiter covers /v1 paths and the MCP route. CORS OPTIONS preflights are exempt, and reads and writes use separate buckets. What that means.
- Which short-video lengths fit one video-trim call? 0.2 to 900 seconds
One Sume video-trim call outputs 0.2 to 900 seconds, so a 3-minute Short fits easily. A 10-minute TikTok ad fits; a 60-minute source does not.
- whisper-1 or gpt-transcribe for subtitles: what OpenAI assigns to each
OpenAI recommends gpt-transcribe, gpt-4o-transcribe-diarize for speakers, whisper-1 for translation and subtitles. Plus the 25 MB limit and a chunking script.
Written by Sume