Format run media URLs are public: copy on webhook or proxy
Sume Format run media lives at durable public media.sume.com URLs. If customer A must not see customer B's video, copy it at receipt time or proxy it.

Every media URL on a Sume Format run receipt is a durable media.sume.com HTTPS URL that does not expire, and anyone holding it can fetch it. If your product promises that customer A never sees customer B's output, copy the file into your own storage when the run finishes, or proxy it through an authenticated route of yours, and store your own URL.
That advice is from the Embed a Format cookbook, section "Map artifacts into your UI", and the Runs and results page repeats the warning.
What does the receipt hand you?
Three media-bearing fields on a terminal completed receipt, per the cookbook.
| Field | Use it for |
|---|---|
primary_output_url | The one thing to show; null when there is no single primary file |
artifacts[] | Everything generated: id, type, url, content_type, size_bytes, width, height, duration_ms, checksum_sha256 |
output | Your structured result; media inside it points at the same URLs |
What does public actually mean here?
The cookbook is blunt: the URL will end up in your logs, your error reports and your customer's browser history. The structured-output docs add that Sume-hosted media is served as public, max-age=31536000, immutable, with expires_at null on the file object, so there is no refresh cycle to lean on.
Nothing in the docs describes a per-customer access control on the URL itself. Treat the URL as a capability link: whoever has it, can read it.
Which should I choose: copy or link?
The cookbook frames it as a decision to make on purpose. Linking is free and instant. Copying costs storage but survives you ever leaving Sume, and it should happen on the webhook, before you mark the record ready, if you want that guarantee.
For per-customer isolation the copy-or-proxy rule applies either way. A copy puts the bytes behind your own authorization; a proxy keeps the Sume URL server-side and never hands it to the browser.
What does a copy-on-receipt step look like?
This stdlib script reads a saved receipt (GET /v1/format-runs/{run_id} body, saved as receipt.json), downloads each artifact and checks the checksum_sha256 field when present. It copies to a local folder; swap the write for your own storage.
import hashlib, json, pathlib, urllib.request
def main():
data = json.load(open("receipt.json"))["data"]
out = pathlib.Path("copies")
out.mkdir(exist_ok=True)
for a in data["artifacts"]:
body = urllib.request.urlopen(a["url"], timeout=60).read()
want = a.get("checksum_sha256")
if want and hashlib.sha256(body).hexdigest() != want:
raise SystemExit(f"checksum mismatch for {a['id']}")
(out / a["id"]).write_bytes(body)
print("copied", a["id"], len(body))
main()Where does the copy run?
Run it in the webhook handler's background step, after you have recorded the event and answered 2xx. A copy inside the request blows the 10-second attempt budget and gets the delivery retried. If the webhook never arrives, read the receipt from result_url and run the same step.
The Runs and results page covers verifying and answering the delivery first.
The structured-output docs describe Sume-hosted media as served with a one-year immutable cache header and a null expires_at, so the copy you take is the same bytes the URL will serve tomorrow. A signed URL with a populated expires_at is possible in principle, but the docs call null the normal case.
Copying also protects you from your own logs. A URL pasted into an error report is a live link, and with a public URL that is enough for anyone who sees the report to open the file.
Sources
Related posts
More in Formats
- Format run spend cap: above the Format cap is honored, null is $500
generation_spend_cap_usd on a Sume Format run may exceed the Format's cap and is not clamped; null runs at the $500 maximum; 0 or over 500 is a 400.
- Format run webhook retries: dedupe on request_id, order by created_at
Sume Format run webhook retries repeat request_id, which equals run_id. Dedupe on it and order deliveries by created_at, which changes per built body.
- Bulk Format runs: 100 items, 16 at once, what completed means
Sume bulk runs take 1 to 100 items at concurrency 1 to 16. A queue marked completed means every item is terminal, not that every item succeeded.
- Format output_schema for partial results: nullable and primary key
How to design a Sume Format output_schema so a run that makes the video but misses a caption still passes: nullable fields, no minItems, and primary_output_key.
Written by Sume