Vidu 24-hour and FLUX 3 signed result links: copy the file first
Vidu result URLs last 24 hours and FLUX 3 signed URLs about 2 hours, or about 10 minutes by another line. Stream the Sume clip to disk and keep the job id.

Treat every result link from a generation API as short-lived: stream the file into your own storage as soon as the job is complete, and store the job id so you can read the record again. On Sume, a completed /v1/videos job gives you unsigned_urls, and the content endpoint takes your API key as a Bearer header.
The two vendors in this week's launches state different lifetimes, and the FLUX 3 page states two of them.
How long do the vendor links live?
These are the figures printed on the vendors' own pages. The FLUX 3 page gives both numbers in different places, so plan for the shorter one.
| Vendor | Stated lifetime | Page |
|---|---|---|
| Vidu task detail | Result URLs valid for 24 hours (url, cover, watermarked) | platform.vidu.com task detail |
| FLUX 3 | Signed result URLs expire about 2 hours after the job finishes | docs.bfl.ai/flux_3 |
| FLUX 3 | The signed result URL is valid for about 10 minutes, so download it promptly | docs.bfl.ai/flux_3 |
What does Sume hand back?
A completed /v1/videos job carries unsigned_urls pointing at the content endpoint on api.sume.com, plus usage.cost. The docs give no expiry for those URLs, so this post claims none. Copy the file anyway if you need it to outlive any link.
How do I stream it to disk?
Check the status first, then stream in chunks so a long clip never sits in memory. The key travels in the header, never in the URL.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def save(job_id, path):
r = requests.get(f"https://api.sume.com/v1/videos/{job_id}",
headers=H, timeout=30)
r.raise_for_status()
job = r.json()
if job["status"] != "completed":
raise SystemExit(f"not ready: {job['status']}")
with requests.get(job["unsigned_urls"][0], headers=H,
stream=True, timeout=120) as s:
s.raise_for_status()
with open(path, "wb") as f:
for chunk in s.iter_content(1 << 20):
f.write(chunk)
return job["usage"]["cost"]
print(save(os.environ["JOB_ID"], "clip.mp4"))Does the same rule apply to Sume artifacts on other routes?
Non-video jobs return artifacts with a media.sume.com url in the job result, and the docs tell you to use those Sume media URLs. The habit is the same either way: read the result once, copy what you need, and record the job id so a later question about that clip has an answer.
What should I store next to the file?
Keep the job id, the model, and usage.cost. With the id you can read GET /v1/jobs/{id}/status later, and GET /v1/jobs/{id}/result once the job is completed. Never log the Bearer header or paste a signed vendor URL into a ticket.
Sources
Related posts
More in Developers
- Vidu 540p has no Sume value: map Vidu resolution names
Vidu Q4 Preview offers 540p, 720p, 1080p, 2K and 4K. Sume's documented values are 480p, 720p, 768p, 1080p, 1K, 2K and 4K, per model. A lookup that fails loudly.
- Vidu 'Authorization: Token' vs Sume 'Bearer': one HTTP client
Vidu wants 'Authorization: Token <key>'; Alibaba Model Studio and Sume want 'Bearer <key>'. A small header helper for a ported client.
- Vidu is_rec and Wan prompt_extend: prompt rewrite vs Sume
Vidu's is_rec and Alibaba's prompt_extend can rewrite your prompt. Sume's documented video fields have no such switch. How to drop them and compare results.
- Vidu's payload pass-through vs Sume: where to keep your order id
Vidu lets you send a payload string that comes back untouched. Sume's video request has no such field; use an Idempotency-Key and your own job table instead.
Written by Sume