Skip to content

Delivery and visibility

A download never streams through the API either. You ask the service for a signed URL and the browser, app or server fetches the bytes from it. This page explains which URL to ask for, who may ask, how long it lives, and how visibility makes files readable for a whole application or for anyone. It is for backend and app developers.

Every URL the service returns is opaque: it may point at an object store, a CDN or the File Service’s own host, depending on where the tenant’s files are stored, and two files can have URLs on different hosts. Use it as returned; never build one or parse it. The answer’s expires_at says how long it lives.

Route Answers
GET P/files/:file_id/download { url, expires_at, mime_type, size, name, version_no } for the original or a rendition
GET P/files/:file_id/content A 302 redirect to the same URL, for HTTP clients that follow redirects
POST P/files/urls Up to 200 URLs in one call, one entry per id in order: what a feed page needs
GET P/files/:file_id/preview What a viewer needs in one call: kind, the best url for it, and every rendition with its own URL

Query and body options:

Option Meaning
disposition attachment (default: the browser saves the file under its name) or inline (the browser shows it)
rendition thumbnail, preview, large, poster, … instead of the original. A rendition that does not exist (yet) answers 404 rendition_not_available with rendition_status; there is no fallback
version An older version’s number; the current one by default
ttl_seconds Machine clients only: from 60 seconds to 24 hours

A URL lives the application’s download_url_ttl_seconds (default 15 minutes). It is bound to one object, one disposition and one content type, supports range requests (video seeking works), and is the same for everyone who holds it. Cache it until a minute before expires_at; never store it.

What you mint Action
A rendition (thumbnail, preview, poster) view
The original, inline, of an image, video, audio file or PDF view
The original as an attachment, or inline for any other type download, and an audit row file.downloaded per URL

A machine client with files:manage or files:read holds both. A user needs them through permissions. In a batch, an id the caller may not read answers error: "missing_action" for that entry, without saying whether the file exists.

GET P/files/:file_id/preview picks for you:

kind url points at
image The preview rendition when it is ready; otherwise the original for the formats browsers display (JPEG, PNG, GIF, WebP, AVIF, BMP); otherwise kind: none until a rendition exists
video The mp4_720p rendition when it is ready, then mp4_1080p, then the original
audio The original
pdf The original, for the browser’s own viewer (its first page is the thumbnail and preview renditions)
text The original as UTF-8 text, with text.truncated when it is longer than 1 MiB
none Nothing can be shown: offer a download

It answers 200 to a caller who may view the file, with every rendition and its URL when it is ready, and 409 scan_pending while the application waits for the scan. Office documents preview as none: they get no rendition. See Previews and renditions.

visibility is a shortcut over the entries for the two common cases of in-app media. Set it on the ticket or later with PATCH P/files/:file_id.

visibility Who can read Needs
private (default) Whoever the permissions allow —
application Every member of the application may view and download it, as if it had an entry for everyone share on the file
public The same, plus a stable, unsigned public_url that anyone with the link can open share, and public_visibility_enabled in the application’s settings (off by default) and at the tenant

A public file’s public_url and public_renditions do not expire and can be cached by browsers and CDNs. They are not permanent either: a new current version replaces the public copy with a new URL, and so does a move of the tenant’s files to another storage (Where files are stored). Keep a copy on your record if you like, but read it from the file again when it stops answering and on file.ready. The URL is unguessable only through the file_id; anyone you give it to can pass it on. Making the file private, trashing it, or a quarantine removes the public copy. Without the application setting, public answers public_visibility_disabled.

Situation Answer
The upload has not completed 409 file_pending
In the trash 409 file_trashed
Quarantined by malware scanning 409 file_quarantined
The application waits for the malware scan before serving files 409 scan_pending, until the scan is clean; also for good when the scan failed or the file is too large to scan and the application blocks unscanned files. See Malware scanning
The caller may not view it 404 file_not_found (never “exists but forbidden” for a file you cannot see)
Viewable, but the action is missing 403 missing_action

URL minting is rate limited: 600 per minute per caller. Mint a feed page in one batch call, not one call per file.