File Endpoints
POST /files/upload
Upload a file.
Auth: Optional (identity from JWT Authorization header)
Request: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to upload |
visibility | string | No | "public" (default) or "private" |
Response 201:
{
"data": {
"id": "uuid",
"original_name": "photo.jpg",
"stored_name": "uuid.jpg",
"mime_type": "image/jpeg",
"size_bytes": 204800,
"visibility": "public",
"uploader_id": "user-uuid",
"created_at": "2026-03-06T12:00:00.000Z"
}
}
Errors:
| Code | Reason |
|---|---|
400 | No file provided, invalid visibility |
413 | File exceeds size limit or per-user quota |
GET /files
List files. Admins see all files; other users see only their own.
Response 200:
{
"data": [
/* array of file metadata objects */
],
"meta": { "total": 5 }
}
GET /files/:id
Get metadata for a single file.
Errors:
| Code | Reason |
|---|---|
403 | Not the owner and not admin |
404 | File not found |
GET /files/:id/download
Download a file. Public files are accessible directly. Private files require a signed URL.
Query Parameters (private files only):
| Parameter | Description |
|---|---|
token | HMAC token from the signed URL |
expires | Unix timestamp from the signed URL |
Response: File stream with appropriate Content-Type and Content-Disposition headers.
Errors:
| Code | Reason |
|---|---|
403 | Private file accessed without valid signed URL |
404 | File not found |
GET /files/:id/signed-url
Generate a time-limited signed URL for a private file.
Auth: Must be the file owner or admin.
Response 200:
{
"data": {
"url": "http://localhost:3000/files/uuid/download?token=abc123&expires=1741300000",
"expires": 1741300000
}
}
Errors:
| Code | Reason |
|---|---|
400 | File is not private |
403 | Not the owner and not admin |
404 | File not found |
DELETE /files/:id
Delete a file from disk and database.
Auth: Must be the file owner or admin.
Response: 204 No Content