Media Library
The media library lets workspace members upload, organize, and download files. Files are stored in S3-compatible object storage (MinIO). Each workspace has its own isolated library.
All media library endpoints require authentication (requireAuth). Access is scoped to workspace members only.
The Library Item Object
{
"id": 1,
"workspace_id": 2,
"uploaded_by": 5,
"uploaded_by_name": "Jane Smith",
"name": "Product Demo.mp4",
"description": "Q1 product walkthrough",
"file_key": "ws-2/550e8400-e29b-41d4-a716-446655440000/demo.mp4",
"file_url": null,
"mime_type": "video/mp4",
"size": 52428800,
"duration": null,
"labels": [
{ "id": 3, "name": "Marketing", "color": "#22c55e" }
],
"created_at": 1711000000,
"updated_at": 1711000000
}
| Field | Type | Description |
|---|---|---|
id | integer | Unique item ID |
workspace_id | integer | Owning workspace |
uploaded_by | integer | User ID of the uploader (null if user deleted) |
uploaded_by_name | string | Display name of the uploader |
name | string | Display name of the file |
description | string | Optional description |
file_key | string | Internal object storage key |
file_url | string/null | Direct URL (currently null; use download endpoint) |
mime_type | string | MIME type (application/pdf or video/mp4) |
size | integer | File size in bytes |
duration | integer/null | Duration in seconds for video files |
labels | array | Assigned workspace labels |
created_at | integer | Unix timestamp |
updated_at | integer | Unix timestamp |
List Library Items
Returns a paginated list of media items for the workspace. Any workspace member can list items.
GET /api/workspaces/:id/library
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
search | string | — | Filter by name (case-insensitive substring match) |
label | integer | — | Filter by label ID |
sort | string | date | Sort field: date, name, or size |
order | string | desc | Sort direction: asc or desc |
limit | integer | 50 | Max items to return (1–100) |
offset | integer | 0 | Pagination offset |
Response:
{
"items": [
{
"id": 1,
"name": "Product Demo.mp4",
"mime_type": "video/mp4",
"size": 52428800,
"uploaded_by_name": "Jane Smith",
"labels": [],
"created_at": 1711000000,
"updated_at": 1711000000
}
],
"total": 1
}
Upload a File
Upload a file to the workspace library. Any workspace member can upload. Files are stored in MinIO object storage.
POST /api/workspaces/:id/library
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to upload |
name | string | No | Display name (defaults to original filename) |
description | string | No | Optional description |
Accepted formats:
| MIME type | Extension |
|---|---|
application/pdf | .pdf |
video/mp4 | .mp4 |
Maximum file size is 100 MB. Uploading a file of an unsupported type or exceeding the size limit returns 400.
Response:
{
"item": {
"id": 1,
"name": "Product Demo.mp4",
"mime_type": "video/mp4",
"size": 52428800,
"labels": [],
"created_at": 1711000000,
"updated_at": 1711000000
}
}
Errors:
| Status | Error |
|---|---|
400 | File is required |
500 | Upload failed: storage service unavailable |
This endpoint also fires a library_item.uploaded webhook event.
Get Download URL
Returns a time-limited presigned URL for downloading a library item directly from object storage. Any workspace member can download.
GET /api/workspaces/:id/library/:itemId/download
Response:
{
"url": "https://storage.example.com/nexus-library/ws-2/550e8400.../demo.mp4?X-Amz-Signature=..."
}
The presigned URL expires after 15 minutes. Do not cache or share it publicly.
Update a Library Item
Rename an item or update its description. Any workspace member can update.
PATCH /api/workspaces/:id/library/:itemId
Request body:
{
"name": "Updated Demo.mp4",
"description": "Updated Q1 walkthrough"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | New display name (cannot be empty) |
description | string | No | New description |
Response:
{
"item": {
"id": 1,
"name": "Updated Demo.mp4",
"description": "Updated Q1 walkthrough",
"labels": [...]
}
}
Delete a Library Item
Deletes the item record and removes the underlying file from object storage. Any workspace member can delete.
DELETE /api/workspaces/:id/library/:itemId
Response:
{ "ok": true }
This endpoint also fires a library_item.deleted webhook event.
Assign a Label to an Item
Add a workspace label to a library item. Any workspace member can assign labels.
POST /api/workspaces/:id/library/:itemId/labels
Request body:
{ "labelId": 3 }
Response: the full updated list of labels on the item.
{
"labels": [
{ "id": 3, "name": "Marketing", "color": "#22c55e" }
]
}
Errors:
| Status | Error |
|---|---|
400 | labelId is required |
404 | Label not found |
Remove a Label from an Item
Remove a workspace label from a library item.
DELETE /api/workspaces/:id/library/:itemId/labels/:labelId
Response: the full updated list of labels remaining on the item.
{
"labels": []
}
Retention Policy
Workspace owners can configure an automatic retention policy. When set, library items older than the configured number of days are automatically deleted (including their object storage files) on server startup.
Get Retention Policy
Owner only.
GET /api/workspaces/:id/retention
Response:
{
"media_retention_days": 90
}
media_retention_days is null when no policy is set (items are kept indefinitely).
Update Retention Policy
Owner only.
PATCH /api/workspaces/:id/retention
Request body:
{
"media_retention_days": 30
}
| Value | Meaning |
|---|---|
7 | Delete items older than 7 days |
30 | Delete items older than 30 days |
60 | Delete items older than 60 days |
90 | Delete items older than 90 days |
180 | Delete items older than 180 days |
365 | Delete items older than 1 year |
null | Keep items indefinitely (no policy) |
Only the values listed above are accepted. Any other integer returns 400. Pass null to disable the policy.
Response:
{
"media_retention_days": 30
}
Webhook Events
The media library dispatches the following workspace webhook events:
| Event | When fired |
|---|---|
library_item.uploaded | After a file is successfully uploaded |
library_item.deleted | After an item is deleted |
See Webhooks for payload format and signature verification.