Store the Sume artifact, not a provider link: what to persist per job
A completed Sume job returns artifacts with id, url, type and content_type. Persist those plus the job id and idempotency key, not provider links.

Save the job id, your idempotency key and, for each artifact, its id, type and content_type, and re-read the job whenever you need a link. The Sume jobs doc says to use the Sume media URLs from the result and that raw provider URLs are not public API outputs, so there is nothing else worth saving.
A completed job looks like result.artifacts[], each entry holding id, url, type and content_type. Fields below come from the jobs and results page, read 2026-10-10.
A table to model
| Field | Store it? | Why |
|---|---|---|
Job id | Yes, as the primary reference | Lets you re-read status, result and usage |
Your Idempotency-Key | Yes, written before the submit | Joins your row to the job after a crash |
Artifact id | Yes | Stable name for the file, independent of its link |
Artifact type and content_type | Yes | Pick the player or the viewer without guessing from the URL |
Artifact url | Cache only | Treat it as a link to re-fetch, not as a permanent address |
| Provider URL or internal model id | No | Not a public output and not promised |
Why not just keep the URL
The docs do not promise how long a media link works, so a design that assumes it lasts forever is making a bet the API has not signed. Keeping the job id costs a few bytes and lets you ask Sume again. If you need the file to live in your own bucket, download it right after completion and store your copy, with the artifact id as its name.
- Download from the Sume URL, not from any URL you saw in a log or a provider tool.
- Store
content_typeso that a PNG and a JPEG are never confused after a re-encode. - Keep the usage row id or the job id next to your invoice line so cost questions can be answered later.
Refreshing a link
On a read, call GET /v1/jobs/{id} and take the artifacts from result. If you listed jobs instead, note that list pages are newest first, so map by id and idempotency_key, not by array position. The pagination post covers the cursor loop.
A schema sketch
A single table is enough for most apps. Key it on your own order or item id, and keep the Sume fields beside it so that every question about a file can be answered from one row.
| Column | Holds | Written when |
|---|---|---|
| item_id | Your own id | Before the submit |
| idempotency_key | The header value | Before the submit |
| job_id | The Sume job id | After the POST returns |
| status | Latest job status | Each poll or webhook |
| artifact_id, type, content_type | From result.artifacts[] | On completion |
| own_copy_path | Where you saved the file | After your download |
Mistakes to avoid
Three habits cause most of the pain. The first is parsing the file type out of the URL; the artifact already tells you its type and content_type, so read those fields. The second is saving the whole job JSON as the only record, which makes simple queries such as "all videos from last week" slow and brittle. The third is forgetting the failed and canceled jobs: store their status and error category too, so a support question about a missing file has an answer.
A short rule helps teams: if a value was returned by Sume and you need it again next month, store its id; if you need the bytes, store your own copy.
- Index
job_idandidempotency_keyas unique columns. - Store the terminal status even when no artifact exists.
- Download inside a background task with a retry, not inside the request that served the user.
Sources
Related posts
More in Developers
- stream: true on the Sume Image API returns 400. What to show instead
Sume image models have no SSE streaming: stream true returns 400 streaming_not_supported. Use async mode and job events for stages, or a webhook for the end.
- Sume API 401 on the dev host: keys only work on their own host
A Sume key works only on the host it was created for. A key from api.sume.com gets 401 on api.dev.sume.com and the reverse. Match key, host, and env var.
- Is there a Sume API test mode? No sandbox key, but two hosts
Sume has no sume_test key. Use the dev host with its own key, cap each run with generation_spend_cap_usd, and mock the rest. What each option costs and covers.
- sume/auto hides which image model ran: pin an id for brand assets
model sume/auto never discloses the family, and job.model stays sume/auto. Why a brand asset set needs a pinned image model id, and how to pin one on Sume.
Written by Sume