Appearance
Files & media URLs
Files that users upload (documents, spreadsheets, images) and files that workflows and apps produce are stored under the API host's /media/ tree and served by the API itself. Because an <img> tag or a download link cannot carry an Authorization header, media is fetched with a signed URL instead of the session token.
How signed URLs work
- Ask the API to sign a media path:
GET /api/v1/media/sign/?path=<media path>. - The response contains a
urlof the form/media/<path>?expires_at=<unix seconds>&user_id=<id>&signature=<hmac>. - Fetch that URL (no headers needed) before it expires. The default lifetime is 1 hour; you may request up to 24 hours with
ttl.
A signed URL is a stateless HMAC — it cannot be revoked before it expires, which is why the lifetime is capped. For a link that must never expire (for example a dashboard embedded in a wiki) create a permanent link with POST /artifacts/links/ (see Studio); permanent links are database rows and can be deleted at any time.
Media paths
Media paths are relative to the media root and always start with the organisation name, then the module, then the username, for example Acme/semantic-search/jane/report.pdf. Endpoints that create files return the path (or a full /media/... URL) in their responses; pass that value to the signing endpoint as-is — percent-encoded or not, it is normalised.
Legacy access modes
The media server also accepts ?token=<access_token> (deprecated — it leaks the session token into logs and browser history) and ?link=<token> for permanent links.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/media/sign/ | Get a signed URL for a media file |
| GET | /media/{path} | Download a media file |
GET /api/v1/media/sign/
Get a signed URL for a media file
Returns a URL that fetches the file without an Authorization header. The default lifetime is 1 hour (MEDIA_SIGNED_URL_TTL_SECONDS); ttl can raise it to at most 24 hours. Signing does not check that the file exists.
Auth: Session token · In the app: Every image, document preview and download link
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
path | string | yes | Media path — with or without a leading /media/, encoded or not. |
ttl | integer | no | Lifetime in seconds. Values above the ceiling are clamped; invalid values fall back to the default. |
Response 200 — Signed URL.
| Field | Type | Description |
|---|---|---|
path | string | Normalised media path. |
url | string | Relative URL to fetch (prefix with the API host). |
expires_at | integer | Unix time (seconds). |
ttl | integer | Seconds until expiry. |
json
{
"path": "Acme/semantic-search/jane/report.pdf",
"url": "/media/Acme/semantic-search/jane/report.pdf?expires_at=1758535272&user_id=42&signature=k8Fh2…",
"expires_at": 1758535272,
"ttl": 3600
}Response 400 — path missing.
json
{
"detail": "path is required"
}Example
bash
TOKEN=...
SIGNED=$(curl -s "https://api.example.com/api/v1/media/sign/?path=Acme/semantic-search/jane/report.pdf" \
-H "Authorization: Token $TOKEN" | python -c "import json,sys; print(json.load(sys.stdin)['url'])")
curl -o report.pdf "https://api.example.com$SIGNED"GET /media/{path}
Download a media file
Serves a stored file. Exactly one of the following must be present:
| Mode | Query parameters | Notes |
|---|---|---|
| Signed URL | expires_at, user_id, signature | Issued by GET /api/v1/media/sign/. Preferred. |
| Permanent link | link | Token from POST /artifacts/links/. Public until the link is deleted. |
| Legacy | token | An access token. Deprecated; the file must live under the caller's own username folder. |
The response is the raw file with its content type; range requests are not supported.
Auth: Signed URL, permanent link, or legacy token (see description) · In the app: Every embedded image, viewer and download
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
path | string | yes | Media path (organisation/module/username/…). |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
expires_at | integer | no | From the signing response. |
user_id | integer | no | From the signing response. |
signature | string | no | From the signing response. |
link | string | no | Permanent-link token. |
token | string | no | Legacy — an access token. |
Response 200 — The file.
Content type: application/octet-stream
Response 403 — Missing or invalid credentials, expired signature, deleted link, or (legacy mode) a path outside the caller's folder.
Content type: text/html
text
Invalid or expired signed URLResponse 404 — No such file.
Example
bash
curl -o report.pdf "https://api.example.com/media/Acme/semantic-search/jane/report.pdf?expires_at=1758535272&user_id=42&signature=k8Fh2..."