Most file storage hands you a URL the moment an upload finishes. It's convenient: drop it in an <img> tag, paste it in a message, done. It's also a decision that's hard to take back, and it's easy to make without noticing.
This guide explains what a public link actually gives away, why "hard to guess" isn't the same as private, how signed links fit in, and how to decide which files should never have a link at all.
A public link is a key
A public file link works for anyone who has it. No account, no password, no check of who's asking. Whoever holds the URL can open the file.
That's exactly what you want for a logo on your marketing site or the audio of a published podcast episode. It's the wrong thing for a customer export, an interview recording, or a transcript of a private call.
Hard to guess isn't private
Good file links are long and random. Stow's public links, for example, contain the file's SHA-256 hash, so nobody will stumble onto one by trying addresses.
But a link doesn't have to be guessed to escape. Links travel:
- pasted into chat apps that fetch a preview,
- written into server logs, error reports and analytics,
- saved in browser history and bookmarks,
- forwarded in an email to someone who forwards it again.
An unguessable link keeps strangers from finding a file. It does nothing once the link itself has been shared or logged.
Cached copies outlive deletion
Public files are usually served with long cache lifetimes, because that's what makes them fast. Stow serves public files with Cache-Control: public, max-age=31536000, immutable: any browser or cache along the way that fetched a file may keep its copy for up to a year.
Deleting the file can't reach into the caches that already have a copy. So the question to ask before making a file public isn't "can I delete it later?" but "is it fine if this is out there for good?"
What about signed links?
A signed link (sometimes called a presigned URL) is a public link with an expiry date. It's a real improvement for files you want to share briefly, like a download that should only work for the next hour.
It is still a bearer link: until it expires, it works for anyone who has it, and whatever was fetched with it may be cached. Signed links shorten the window. They don't close it.
Files with no link at all
The other option is for a file to have no link. A private file can only be read by a request that proves it's allowed, with an API key or a signed-in session, every time.
In Stow, that's a choice you make at upload:
curl -X POST https://api.usestow.com/v1/assets \
-H "Authorization: Bearer $STOW_API_KEY" \
-F file=@interview.mp3 \
-F visibility=private
The file comes back with "public_url": null. Your apps read it with GET /v1/assets/:id/content and a key from your account; any other account gets a 404. Private files are kept apart from public ones, no public address serves them, and they're sent with Cache-Control: private, no-store. Visibility can't be changed after upload, so a private file can't be made public later by mistake.
Public or private? A quick checklist
Fine as public links:
- images and video for your website or app
- published audio, like podcast episodes that are already public
- open data and documents you'd happily post anywhere
Keep private:
- transcripts and recordings of conversations
- exports with customer or personal data
- source files and drafts that haven't been published
- licensed or copyrighted material you don't have the right to redistribute
- anything an AI agent produced that you haven't reviewed
When in doubt, make it private. You can always upload a public copy later; you can't recall a link.
Defaults matter
Over the API, Stow files are public by default, because most files apps upload (images, media, assets for a site) are meant to be shown. That's why the choice is worth making on purpose for everything else.
For AI agents it's the other way round. Files uploaded through the Stow MCP server are private unless the agent asks for a public link, and a public upload that looks like it contains a secret, like an API key or a password, is refused.
The private files section of the docs has the details, and Private file storage shows the whole setup on one page.