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.

4 min readSume
All posts

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.

Result link lifetimes stated by each vendor (read 2026-10-09)
VendorStated lifetimePage
Vidu task detailResult URLs valid for 24 hours (url, cover, watermarked)platform.vidu.com task detail
FLUX 3Signed result URLs expire about 2 hours after the job finishesdocs.bfl.ai/flux_3
FLUX 3The signed result URL is valid for about 10 minutes, so download it promptlydocs.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

All Developers posts

Written by Sume