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.
The routes
Section titled “The routes”| 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.
Which action a URL needs
Section titled “Which action a URL needs”| 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.
The preview call
Section titled “The preview call”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
Section titled “Visibility”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.
When a file cannot be served
Section titled “When a file cannot be served”| 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.