Your outputs have a half-life: what media providers keep, and for how long

The support ticket arrives on a Monday: a customer's gallery — every image their users generated last quarter — is a wall of broken thumbnails. Nothing was deleted. Nothing failed. The product did exactly what it was built to do, which was to save the URL the provider returned and trust it. The URLs did what they were built to do, too: they expired.
The numbers nobody puts on the pricing page
Generative media providers are inference companies. They sell GPU seconds; storing your outputs forever is a cost center they never signed up for. So they don't:
| Provider | Output retention | What it means |
|---|---|---|
| Replicate | ~1 hour | Output URLs go dark before your standup ends |
| fal | ~7 days | A sprint. Long enough to forget, short enough to hurt |
| Others | varies, often unstated | Check the docs — then check the ToS, they differ |
None of this is hidden, exactly. It's in the docs, usually phrased as a gentle suggestion that you download your files. But the default integration path — call the API, get a URL, store the URL — produces a product that works flawlessly in the demo, through the launch, and for about as long as the retention window. Then it rots, silently, starting with your oldest and most attached users.
A provider URL is not storage. It's a countdown that returns 200 until it doesn't.
The providers aren't wrong
It's worth saying: this is a reasonable trade for them to make. Media outputs are enormous — a few seconds of video is tens of megabytes, and a busy provider generates petabytes of it. Hosting that forever, for free, for customers who may never come back, would be lighting money on fire. Retention windows are the honest version of that math. The dishonest version would be charging you inference prices that quietly include eternal storage you didn't ask for.
The mistake is on the integration side: treating an inference vendor's scratch space as your system of record. Your users think of their generations as their stuff. Their stuff should live in storage you control the lifecycle of.
What owning your masters actually takes
"Just download the file" is the right idea and an incomplete instruction. The version that holds up in production:
- Persist inside the window, every time. The download has to happen between job completion and URL expiry — which for a one-hour window means it's part of the job lifecycle, not a nightly batch. If persistence fails, that's an incident, not a warning log.
- Byte-exact, hash on the way in. Stream the output to your bucket untouched and compute the sha256 in the same pass. The hash proves, forever, that what you hold is what the model produced — and untouched bytes are the only way provider-embedded Content Credentials survive.
- Record the act. When was it fetched, from where, how many bytes, what hash. When someone asks in a year whether the published file is the original, "yes" is not evidence; a ledger entry with a digest is.
- Serve from your storage, always. The provider URL should never reach your database, your frontend, or — worst case, and we've seen it — your users' bookmarks.
The broken-gallery ticket is entirely preventable, and the prevention is unglamorous: treat every provider output as a file with a fuse lit, and put it somewhere permanent before the fuse runs out. Storage is the cheapest part of a media pipeline. Losing your users' work is the most expensive.