Complete REST API documentation for the Catalogizer backend (catalog-api). All endpoints are served under the base URL http://localhost:8080.
- Overview
- Authentication
- Catalog Browsing
- Search
- Download
- File Copy Operations
- Media Operations
- Recommendations
- Subtitles
- Storage
- Statistics
- GET /api/v1/stats/directories/by-size
- GET /api/v1/stats/duplicates/count
- GET /api/v1/stats/overall
- GET /api/v1/stats/smb/{smb_root}
- GET /api/v1/stats/filetypes
- GET /api/v1/stats/sizes
- GET /api/v1/stats/duplicates
- GET /api/v1/stats/duplicates/groups
- GET /api/v1/stats/access
- GET /api/v1/stats/growth
- GET /api/v1/stats/scans
- SMB Discovery
- Conversion
- User Management
- Role Management
- Configuration
- GET /api/v1/configuration
- POST /api/v1/configuration/test
- GET /api/v1/configuration/status
- GET /api/v1/configuration/wizard/step/{step_id}
- POST /api/v1/configuration/wizard/step/{step_id}/validate
- POST /api/v1/configuration/wizard/step/{step_id}/save
- GET /api/v1/configuration/wizard/progress
- POST /api/v1/configuration/wizard/complete
- Error Reporting
- POST /api/v1/errors/report
- POST /api/v1/errors/crash
- GET /api/v1/errors/reports
- GET /api/v1/errors/reports/{id}
- PUT /api/v1/errors/reports/{id}/status
- GET /api/v1/errors/crashes
- GET /api/v1/errors/crashes/{id}
- PUT /api/v1/errors/crashes/{id}/status
- GET /api/v1/errors/statistics
- GET /api/v1/errors/crash-statistics
- GET /api/v1/errors/health
- Log Management
- POST /api/v1/logs/collect
- GET /api/v1/logs/collections
- GET /api/v1/logs/collections/{id}
- GET /api/v1/logs/collections/{id}/entries
- POST /api/v1/logs/collections/{id}/export
- GET /api/v1/logs/collections/{id}/analyze
- POST /api/v1/logs/share
- GET /api/v1/logs/share/{token}
- DELETE /api/v1/logs/share/{id}
- GET /api/v1/logs/stream
- GET /api/v1/logs/statistics
- Health and Metrics
- Global Middleware
- Error Handling
- Rate Limiting
| Property | Value |
|---|---|
| Base URL | http://localhost:8080 |
| API Version | v1 |
| Auth Method | JWT Bearer Token |
| Content Type | application/json |
| Database | SQLite (dev) / PostgreSQL (prod) |
All API routes (except /health, /metrics, and /api/v1/auth/*) require a valid JWT token in the Authorization header:
Authorization: Bearer <jwt_token>
Authentication endpoints are under /api/v1/auth. These endpoints have stricter rate limiting (5 requests/minute) and do not require a JWT token (except /me).
Authenticate a user and receive JWT tokens.
| Property | Value |
|---|---|
| Auth Required | No |
| Rate Limit | 5/min |
| Permission | None |
Request Body:
{
"username": "admin",
"password": "securepassword",
"device_info": {
"device_type": "desktop",
"platform": "linux",
"app_version": "3.0.0"
},
"remember_me": true
}Success Response (200):
{
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"role_id": 1,
"role": {
"id": 1,
"name": "admin",
"permissions": ["*"]
},
"is_active": true,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
},
"session_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2024-01-02T00:00:00Z"
}Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid request format"} |
Malformed JSON |
| 401 | {"error": "invalid credentials"} |
Wrong username/password |
Register a new user account.
| Property | Value |
|---|---|
| Auth Required | No |
| Rate Limit | 5/min |
| Permission | None |
Request Body:
{
"username": "newuser",
"email": "newuser@example.com",
"password": "securepassword",
"first_name": "John",
"last_name": "Doe"
}| Field | Type | Required | Validation |
|---|---|---|---|
username |
string | Yes | - |
email |
string | Yes | Valid email |
password |
string | Yes | Min 8 characters |
first_name |
string | Yes | - |
last_name |
string | Yes | - |
Success Response (201):
Returns the created User object (see API_SCHEMAS.md).
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "<validation details>"} |
Validation failure |
| 409 | {"error": "Username already exists"} |
Duplicate username |
| 409 | {"error": "Email already exists"} |
Duplicate email |
Refresh an expired access token using a refresh token.
| Property | Value |
|---|---|
| Auth Required | No |
| Rate Limit | 5/min |
Request Body:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}Success Response (200):
{
"session_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2024-01-02T00:00:00Z"
}Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid request format"} |
Malformed JSON |
| 401 | {"error": "invalid refresh token"} |
Expired or invalid token |
Invalidate the current session token.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 5/min |
Success Response (200):
{
"message": "Logged out successfully"
}Get the currently authenticated user's profile.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 5/min |
Success Response (200):
Returns the current User object (see API_SCHEMAS.md).
Browse the file catalog across all configured storage roots (SMB, FTP, NFS, WebDAV, local).
List all available storage root directories.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Success Response (200):
{
"roots": [
"nas-media",
"nas-backup",
"local-storage"
]
}List files and directories at the specified path.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
sort_by |
string | name |
Sort field: name, size, modified |
sort_order |
string | asc |
Sort order: asc, desc |
limit |
int | 100 |
Max results to return |
offset |
int | 0 |
Pagination offset |
Example Request:
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/catalog/nas-media/movies?sort_by=size&sort_order=desc&limit=50"Success Response (200):
{
"files": [
{
"id": 1024,
"storage_root_id": 1,
"storage_root_name": "nas-media",
"path": "movies/The Matrix (1999)",
"name": "The Matrix (1999)",
"size": 4294967296,
"is_directory": true,
"mime_type": null,
"created_at": "2024-01-15T10:30:00Z",
"modified_at": "2024-01-15T10:30:00Z"
}
],
"count": 1,
"limit": 50,
"offset": 0
}Get detailed information about a specific file or directory.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Success Response (200):
Returns a FileInfo object (see API_SCHEMAS.md).
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Path is required"} |
Empty path |
| 404 | {"error": "File not found"} |
Path does not exist |
Search for files and directories using various criteria.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | Yes | - | Search term (filename match) |
path |
string | No | - | Path filter |
extension |
string | No | - | File extension filter |
mime_type |
string | No | - | MIME type filter |
min_size |
int | No | - | Minimum file size (bytes) |
max_size |
int | No | - | Maximum file size (bytes) |
smb_roots |
string | No | - | Comma-separated storage root names |
is_directory |
bool | No | - | Filter by directory status |
sort_by |
string | No | name |
Sort field |
sort_order |
string | No | asc |
Sort direction |
limit |
int | No | 100 |
Max results |
offset |
int | No | 0 |
Pagination offset |
Example Request:
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/search?query=matrix&extension=mkv&smb_roots=nas-media"Success Response (200):
{
"files": [...],
"total": 15,
"count": 15,
"limit": 100,
"offset": 0
}Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Search query is required"} |
Missing query parameter |
Find groups of duplicate files within a storage root.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
smb_root |
string | Yes | - | Storage root name to search |
min_count |
int | No | 2 |
Minimum duplicates per group |
limit |
int | No | 50 |
Max groups to return |
Success Response (200):
{
"groups": [
{
"id": 42,
"file_count": 3,
"total_size": 12884901888,
"created_at": "2024-01-10T08:00:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"count": 1
}Download a single file by its database ID.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
| Response Type | application/octet-stream |
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
int | File ID |
Response Headers:
Content-Disposition: attachment; filename="movie.mkv"
Content-Type: application/octet-stream
Content-Length: 4294967296
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid file ID"} |
Non-numeric ID |
| 400 | {"error": "Cannot download directory as single file"} |
Path is a directory |
| 404 | {"error": "File not found"} |
File does not exist |
Download a directory as a compressed archive.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
| Response Type | application/zip or application/gzip |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | zip |
Archive format: zip, tar, tar.gz |
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid format. Supported: zip, tar, tar.gz"} |
Unsupported format |
| 400 | {"error": "Directory too large for download", "total_size": ..., "max_size": ...} |
Exceeds max size |
| 404 | {"error": "Directory not found or empty"} |
Path does not exist |
Create and download an archive from multiple specified file paths.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"paths": [
"movies/The Matrix (1999)/The.Matrix.mkv",
"movies/Inception (2010)/Inception.mkv"
],
"format": "zip",
"smb_root": "nas-media"
}| Field | Type | Required | Description |
|---|---|---|---|
paths |
string[] | Yes | Array of file paths to include |
format |
string | No | zip (default), tar, tar.gz |
smb_root |
string | No | Storage root name |
Copy a file to a storage location.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"source_path": "/tmp/upload/document.pdf",
"dest_path": "/documents/archive/document.pdf",
"storage_id": "local"
}| Field | Type | Required | Description |
|---|---|---|---|
source_path |
string | Yes | Source file path |
dest_path |
string | Yes | Destination file path |
storage_id |
string | Yes | Target storage root ID |
Success Response (200):
{
"message": "File copied to storage successfully",
"source": "/tmp/upload/document.pdf",
"destination": "/documents/archive/document.pdf",
"storage_id": "local"
}Copy a file from a remote storage (SMB) to local filesystem.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"source_path": "nas-media:movies/movie.mkv",
"destination_path": "/local/downloads/movie.mkv",
"overwrite": false
}| Field | Type | Required | Description |
|---|---|---|---|
source_path |
string | Yes | Source in host:path format |
destination_path |
string | Yes | Local destination path |
overwrite |
bool | No | Overwrite existing files (default: false) |
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid source format. Use 'host:path'"} |
Bad source format |
| 409 | {"error": "Destination file already exists"} |
File exists and overwrite=false |
Upload a file from local filesystem to SMB storage.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
| Content-Type | multipart/form-data |
Form Fields:
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | File to upload |
destination |
string | Yes | Destination in host:path format |
overwrite |
string | No | "true" to overwrite existing files |
Success Response (200):
{
"message": "File uploaded successfully",
"filename": "document.pdf",
"destination": "nas-media:documents/document.pdf",
"size": 1048576
}Get detailed media item information by ID.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Success Response (200):
{
"id": 42,
"title": "The Matrix (1999)",
"media_type": "video",
"year": 1999,
"description": "A computer hacker learns about the true nature of reality.",
"cover_image": "https://image.tmdb.org/t/p/w500/f89U3ADr1oiB1s9GkdPOEpXUk5H.jpg",
"rating": 8.7,
"quality": "1080p",
"file_size": 4294967296,
"duration": 8160,
"directory_path": "/movies/The Matrix (1999)",
"smb_path": "//nas/media/movies/The Matrix (1999)",
"created_at": "2024-01-15 10:30:00",
"updated_at": "2024-01-15 10:30:00",
"external_metadata": [],
"versions": [],
"is_favorite": true,
"watch_progress": 0.75,
"last_watched": "2024-01-20 20:00:00",
"is_downloaded": false
}Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid media ID"} |
Non-numeric ID |
| 404 | {"error": "Media not found"} |
Media does not exist |
Update watch progress for a media item.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"progress": 0.75
}| Field | Type | Required | Validation |
|---|---|---|---|
progress |
float | Yes | 0.0 to 1.0 |
Success Response (200):
{
"success": true,
"message": "Watch progress updated successfully"
}Update the favorite status for a media item.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"favorite": true
}Success Response (200):
{
"success": true,
"message": "Favorite status updated successfully"
}Get media items similar to a given media item.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
media_id |
int | Media item ID |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
max_local_items |
int | 10 |
Max local results |
max_external_items |
int | 5 |
Max external results |
include_external |
bool | false |
Include external API results |
similarity_threshold |
float | 0.3 |
Minimum similarity score |
Success Response (200):
{
"media_id": "42",
"local_items": [...],
"external_items": [...],
"total_local": 8,
"total_external": 5
}Get trending media items based on recent activity.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
media_type |
string | - | Filter by type: video, audio, etc. |
limit |
int | 20 |
Max results |
time_range |
string | week |
Time range: day, week, month, year |
Success Response (200):
{
"items": [
{
"id": 100,
"title": "Trending Movie 1",
"media_type": "video",
"rating": 8.2,
"is_favorite": false,
"watch_progress": 0,
"is_downloaded": true
}
],
"media_type": "video",
"time_range": "week",
"generated_at": "2024-01-20T12:00:00Z"
}Get personalized recommendations based on viewing history.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
int | 20 |
Max results |
Success Response (200):
{
"user_id": 1,
"items": [...],
"generated_at": "2024-01-20T12:00:00Z"
}Simple test endpoint for the recommendation system.
Success Response (200):
{
"message": "Simple recommendation works!"
}Search for subtitles across multiple providers.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
media_path |
string | Yes | Path to the media file |
title |
string | No | Media title override |
year |
int | No | Release year |
season |
int | No | TV season number |
episode |
int | No | TV episode number |
languages |
string | No | Comma-separated language codes |
providers |
string | No | Comma-separated provider names |
Available Providers: opensubtitles, subdb, yifysubtitles, subscene, addic7ed
Success Response (200):
{
"success": true,
"results": [
{
"id": "os-12345",
"title": "The Matrix",
"language": "English",
"language_code": "en",
"provider": "opensubtitles",
"format": "srt",
"rating": 9.2,
"download_count": 150000
}
],
"count": 1
}Download a specific subtitle by result ID.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Rate Limit | 100/min |
Request Body:
{
"media_item_id": 42,
"result_id": "os-12345",
"language": "en"
}Success Response (200):
{
"success": true,
"track": {
"id": "sub-001",
"language": "English",
"language_code": "en",
"format": "srt",
"is_default": false,
"is_forced": false
}
}Get all subtitle tracks for a media item.
Success Response (200):
{
"success": true,
"subtitles": [
{
"id": "sub-001",
"language": "English",
"language_code": "en",
"format": "srt"
}
],
"media_item_id": 42
}Verify if a subtitle is properly synchronized with its media.
Success Response (200):
{
"success": true,
"sync_result": {
"is_synced": true,
"offset_ms": 150,
"confidence": 0.95
}
}Translate a subtitle to another language.
Request Body:
{
"subtitle_id": "sub-001",
"source_language": "en",
"target_language": "es"
}Success Response (200):
{
"success": true,
"translated_track": {
"id": "sub-002",
"language": "Spanish",
"language_code": "es",
"format": "srt"
}
}Upload a subtitle file for a media item.
| Property | Value |
|---|---|
| Content-Type | multipart/form-data |
Form Fields:
| Field | Type | Required | Description |
|---|---|---|---|
media_item_id |
int | Yes | Media item ID |
language |
string | Yes | Language name (e.g., "English") |
language_code |
string | Yes | ISO 639-1 code (e.g., "en") |
file |
file | Yes | Subtitle file (.srt, .vtt, .ass, .txt) |
Get the list of supported subtitle languages.
Success Response (200):
{
"success": true,
"languages": [
{"code": "en", "name": "English", "native_name": "English"},
{"code": "es", "name": "Spanish", "native_name": "Espanol"},
{"code": "fr", "name": "French", "native_name": "Francais"},
{"code": "de", "name": "German", "native_name": "Deutsch"},
{"code": "ru", "name": "Russian", "native_name": "Russkij"}
],
"count": 19
}Get the list of supported subtitle providers.
Success Response (200):
{
"success": true,
"providers": [
{"provider": "opensubtitles", "name": "OpenSubtitles", "description": "Large subtitle database with multiple languages", "supported": true},
{"provider": "subdb", "name": "SubDB", "description": "Hash-based subtitle matching", "supported": true},
{"provider": "yifysubtitles", "name": "YIFY Subtitles", "description": "Subtitles for YIFY movie releases", "supported": true},
{"provider": "subscene", "name": "Subscene", "description": "Community-driven subtitle site", "supported": true},
{"provider": "addic7ed", "name": "Addic7ed", "description": "TV show subtitles with translations", "supported": true}
],
"count": 5
}Get all available storage root configurations.
Success Response (200):
{
"roots": [
{"id": "local", "name": "Local Storage", "path": "/data/storage"},
{"id": "smb", "name": "SMB Storage", "path": "smb://server/share"}
]
}List files in a storage path.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
storage_id |
string | Yes | Storage root ID |
Success Response (200):
{
"path": "/documents",
"storage_id": "local",
"files": [...]
}Get directories sorted by total size.
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
smb_root |
string | Yes | - | Storage root name |
limit |
int | No | 50 |
Max results |
Success Response (200):
{
"directories": [
{
"path": "/movies/4K",
"name": "4K",
"storage_root_name": "nas-media",
"file_count": 150,
"total_size": 1099511627776
}
],
"count": 10
}Get statistics about duplicate files.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
smb_root |
string | No | Storage root name |
Success Response (200):
{
"duplicate_groups": 42,
"total_duplicates": 125,
"total_wasted_space": 53687091200,
"smb_root": "nas-media"
}Get comprehensive catalog statistics.
Success Response (200):
{
"success": true,
"data": {
"total_files": 25000,
"total_directories": 3200,
"total_size": 5497558138880,
"total_duplicates": 125,
"duplicate_groups": 42,
"storage_roots_count": 5,
"active_storage_roots": 4,
"last_scan_time": 1705312200
}
}Get statistics for a specific storage root.
Success Response (200):
{
"success": true,
"data": {
"name": "nas-media",
"total_files": 15000,
"total_directories": 2000,
"total_size": 3298534883328,
"duplicate_files": 80,
"duplicate_groups": 25,
"last_scan_time": 1705312200,
"is_online": true
}
}Get file type distribution statistics.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
smb_root |
string | - | Storage root filter |
limit |
int | 50 |
Max results (max 1000) |
Success Response (200):
{
"success": true,
"data": [
{"file_type": "video", "extension": ".mkv", "count": 5000, "total_size": 2748779069440, "average_size": 549755813},
{"file_type": "audio", "extension": ".flac", "count": 12000, "total_size": 549755813888, "average_size": 45812984}
]
}Get file size distribution.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
smb_root |
string | Storage root filter |
Success Response (200):
{
"success": true,
"data": {
"tiny": 500,
"small": 3000,
"medium": 8000,
"large": 10000,
"huge": 3000,
"massive": 500
}
}Size buckets: tiny (<1KB), small (1KB-1MB), medium (1MB-10MB), large (10MB-100MB), huge (100MB-1GB), massive (>1GB).
Get duplicate file statistics.
Success Response (200):
{
"success": true,
"data": {
"total_duplicates": 125,
"duplicate_groups": 42,
"wasted_space": 53687091200,
"largest_duplicate_group": 8,
"average_group_size": 2.97
}
}Get the largest duplicate groups.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
sort_by |
string | count |
count or size |
limit |
int | 20 |
Max results (max 100) |
smb_root |
string | - | Storage root filter |
Get file access pattern statistics.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
smb_root |
string | - | Storage root filter |
days |
int | 30 |
Analysis period (max 365) |
Get storage growth trends over time.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
smb_root |
string | - | Storage root filter |
months |
int | 12 |
Analysis period (max 60) |
Success Response (200):
{
"success": true,
"data": {
"monthly_growth": [
{"month": "2024-01", "files_added": 500, "size_added": 274877906944, "total_files": 25000, "total_size": 5497558138880}
],
"total_growth_rate": 12.5,
"file_growth_rate": 8.3,
"size_growth_rate": 15.2
}
}Get scan operation history.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
smb_root |
string | - | Storage root filter |
limit |
int | 50 |
Max results (max 1000) |
offset |
int | 0 |
Pagination offset |
Success Response (200):
{
"success": true,
"data": {
"scans": [
{
"id": 23,
"storage_root_id": 1,
"scan_type": "full",
"status": "completed",
"start_time": "2024-01-15T10:00:00Z",
"end_time": "2024-01-15T10:45:00Z",
"files_processed": 25000,
"files_added": 150,
"files_updated": 30,
"files_deleted": 5,
"error_count": 0
}
],
"total_count": 100,
"limit": 50,
"offset": 0
}
}Discover available SMB shares on a host.
Request Body:
{
"host": "192.168.1.100",
"username": "user",
"password": "password",
"domain": "WORKGROUP"
}| Field | Type | Required | Description |
|---|---|---|---|
host |
string | Yes | SMB host address |
username |
string | Yes | Authentication username |
password |
string | Yes | Authentication password |
domain |
string | No | Windows domain |
Success Response (200):
Returns an array of SMBShareInfo objects.
Discover SMB shares using query parameters (for testing).
Query Parameters:
| Parameter | Type | Required |
|---|---|---|
host |
string | Yes |
username |
string | Yes |
password |
string | Yes |
domain |
string | No |
Test connectivity to an SMB share.
Request Body:
{
"host": "192.168.1.100",
"port": 445,
"share": "media",
"username": "user",
"password": "password",
"domain": "WORKGROUP"
}Success Response (200):
{
"success": true,
"host": "192.168.1.100",
"share": "media",
"username": "user",
"connection": true
}Test SMB connection using query parameters.
Query Parameters:
| Parameter | Type | Required | Default |
|---|---|---|---|
host |
string | Yes | - |
share |
string | Yes | - |
username |
string | Yes | - |
password |
string | Yes | - |
domain |
string | No | - |
port |
int | No | 445 |
Browse files and directories in an SMB share.
Request Body:
{
"host": "192.168.1.100",
"port": 445,
"share": "media",
"username": "user",
"password": "password",
"domain": "WORKGROUP",
"path": "movies"
}Success Response (200):
Returns an array of SMBFileEntry objects.
Create a new media format conversion job.
| Property | Value |
|---|---|
| Auth Required | Bearer Token |
| Permission | conversion.create |
Request Body:
{
"source_path": "/media/video.mp4",
"target_path": "/media/video.mp3",
"source_format": "mp4",
"target_format": "mp3",
"conversion_type": "audio",
"quality": "high",
"priority": 1,
"settings": "{\"bitrate\": \"320k\"}",
"scheduled_for": "2024-01-20T10:00:00Z"
}Success Response (200):
Returns a ConversionJob object (see API_SCHEMAS.md).
List conversion jobs for the current user.
| Property | Value |
|---|---|
| Permission | conversion.view |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
status |
string | - | Filter by status: pending, running, completed, failed, cancelled |
limit |
int | 50 |
Max results (max 100) |
offset |
int | 0 |
Pagination offset |
Success Response (200):
Returns an array of ConversionJob objects.
Get a specific conversion job by ID.
Error Responses:
| Status | Body | Condition |
|---|---|---|
| 400 | {"error": "Invalid job ID"} |
Non-numeric ID |
| 404 | {"error": "Job not found"} |
Job does not exist |
Cancel a running conversion job.
| Property | Value |
|---|---|
| Permission | conversion.manage |
Success Response (200):
{
"message": "Job cancelled successfully"
}Get all supported conversion formats.
| Property | Value |
|---|---|
| Permission | conversion.view |
Success Response (200):
{
"video": {
"input": ["mp4", "mkv", "avi", "mov", "wmv", "flv", "webm"],
"output": ["mp4", "mkv", "avi", "webm"]
},
"audio": {
"input": ["mp3", "flac", "wav", "aac", "ogg", "wma", "m4a"],
"output": ["mp3", "flac", "wav", "aac", "ogg"]
},
"document": {
"input": ["pdf", "doc", "docx", "txt", "rtf"],
"output": ["pdf", "txt"]
},
"image": {
"input": ["jpg", "png", "gif", "bmp", "webp", "tiff"],
"output": ["jpg", "png", "webp"]
}
}All user management endpoints require a JWT token and appropriate permissions.
Create a new user.
| Property | Value |
|---|---|
| Permission | user.create |
Request Body:
{
"username": "johndoe",
"email": "john@example.com",
"password": "securepassword123",
"role_id": 2,
"first_name": "John",
"last_name": "Doe",
"display_name": "John D.",
"time_zone": "America/New_York",
"language": "en",
"is_active": true
}Success Response (201):
Returns the created User object.
Error Responses:
| Status | Condition |
|---|---|
| 400 | Password validation failure |
| 409 | Username or email already exists |
List all users with pagination.
| Property | Value |
|---|---|
| Permission | user.view |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
int | 50 |
Max results (max 100) |
offset |
int | 0 |
Pagination offset |
Success Response (200):
{
"users": [...],
"total_count": 150,
"limit": 50,
"offset": 0
}Get a specific user by ID. Users can view their own profile; viewing other users requires user.view permission.
Update a user's information. Users can update their own profile; updating other users requires user.update permission. Changing role_id or is_active requires user.manage permission.
Request Body (all fields optional):
{
"username": "newusername",
"email": "newemail@example.com",
"first_name": "John",
"last_name": "Doe",
"display_name": "John D.",
"avatar_url": "https://example.com/avatar.jpg",
"time_zone": "America/New_York",
"language": "en",
"role_id": 2,
"is_active": true,
"settings": {"theme": "dark"}
}Delete a user account.
| Property | Value |
|---|---|
| Permission | user.delete |
Success Response: 204 No Content
Error Responses:
| Status | Condition |
|---|---|
| 400 | Attempting to delete own account |
Reset a user's password (admin operation).
| Property | Value |
|---|---|
| Permission | user.manage |
Request Body:
{
"new_password": "newSecurePassword123"
}Lock a user account until a specified time.
| Property | Value |
|---|---|
| Permission | user.manage |
Request Body:
{
"lock_until": "2024-02-01T00:00:00Z"
}Unlock a locked user account.
| Property | Value |
|---|---|
| Permission | user.manage |
Success Response (200):
{
"message": "Account unlocked successfully"
}All role management endpoints require system.admin permission.
Create a new role.
Request Body:
{
"name": "editor",
"description": "Content editor with media management access",
"permissions": ["media.view", "media.edit", "media.upload"]
}Success Response (201):
Returns the created Role object.
List all roles.
Success Response (200):
Returns an array of Role objects.
Get a specific role by ID.
Update a role. System roles cannot be modified.
Request Body:
{
"name": "editor",
"description": "Updated description",
"permissions": ["media.view", "media.edit", "media.upload", "media.delete"]
}Delete a role. System roles and roles assigned to users cannot be deleted.
Success Response: 204 No Content
Get the complete permission catalog organized by category.
Success Response (200):
{
"user_management": {
"create_user": "user.create",
"view_user": "user.view",
"edit_user": "user.update",
"delete_user": "user.delete",
"manage_users": "user.manage"
},
"media_management": {
"view_media": "media.view",
"upload_media": "media.upload",
"edit_media": "media.edit",
"delete_media": "media.delete"
},
"share_management": {
"view_shares": "share.view",
"create_shares": "share.create",
"edit_shares": "share.edit",
"delete_shares": "share.delete"
},
"system": {
"system_admin": "system.admin",
"view_analytics": "analytics.view",
"export_data": "analytics.export",
"manage_settings": "system.configure"
}
}Get the current system configuration schema.
| Property | Value |
|---|---|
| Permission | system.configure |
Test a configuration without applying it.
| Property | Value |
|---|---|
| Permission | system.admin |
Request Body: A Configuration object.
Success Response (200):
{
"is_valid": true,
"errors": [],
"warnings": ["SMTP not configured"]
}Get system component health status.
| Property | Value |
|---|---|
| Permission | system.configure |
Success Response (200):
{
"status": "healthy",
"version": "3.0.0",
"uptime": "24h 30m",
"components": {
"database": "healthy",
"storage": "healthy",
"authentication": "healthy",
"media_conversion": "healthy",
"sync": "healthy"
}
}Get a specific setup wizard step definition.
Validate data for a specific wizard step.
Save progress for a specific wizard step.
Get the current wizard progress for the authenticated user.
Complete the setup wizard and apply the configuration.
Submit an error report.
| Property | Value |
|---|---|
| Permission | report.create |
Request Body:
{
"level": "error",
"message": "Failed to process media file",
"error_code": "MEDIA_PROCESS_ERROR",
"component": "media_processor",
"stack_trace": "goroutine 1 [running]:...",
"context": {"file_id": 123, "operation": "thumbnail_generation"},
"user_agent": "Mozilla/5.0...",
"url": "/api/v1/media/123/thumbnail"
}Success Response (200):
Returns the created ErrorReport object.
Submit a crash report.
| Property | Value |
|---|---|
| Permission | report.create |
Request Body:
{
"signal": "SIGSEGV",
"message": "Segmentation fault in media decoder",
"stack_trace": "...",
"context": {"media_id": 42}
}List error reports with filtering.
| Property | Value |
|---|---|
| Permission | report.view |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
string | Filter by level: debug, info, warning, error, fatal |
component |
string | Filter by component |
status |
string | Filter by status: new, in_progress, resolved, ignored |
start_date |
string | Start date (YYYY-MM-DD) |
end_date |
string | End date (YYYY-MM-DD) |
limit |
int | Max results |
offset |
int | Pagination offset |
Get a specific error report.
Update error report status.
Request Body:
{
"status": "resolved"
}List crash reports with filtering (same parameters as error reports, with signal instead of level/component).
Get a specific crash report.
Update crash report status.
Get error reporting statistics.
Success Response (200):
{
"total_errors": 150,
"errors_by_level": {"error": 100, "warning": 40, "fatal": 10},
"errors_by_component": {"media_processor": 80, "auth": 30, "storage": 40},
"recent_errors": 15,
"resolved_errors": 120,
"avg_resolution_time": 3600.5
}Get crash reporting statistics.
Get system health based on error and crash data.
| Property | Value |
|---|---|
| Permission | system.admin |
All log management endpoints require system.admin permission.
Create a new log collection.
Request Body:
{
"name": "Debug Session 2024-01-20",
"description": "Investigating media processing issue",
"components": ["api", "media_processor", "storage"],
"log_level": "debug",
"start_time": "2024-01-20T00:00:00Z",
"end_time": "2024-01-20T23:59:59Z",
"filters": {"include_stack_traces": true}
}List log collections.
Query Parameters:
| Parameter | Type | Default |
|---|---|---|
limit |
int | 20 |
offset |
int | 0 |
Get a specific log collection.
Get log entries for a collection.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
string | Filter by level |
component |
string | Filter by component |
search |
string | Full-text search |
start_time |
string | ISO 8601 start time |
end_time |
string | ISO 8601 end time |
limit |
int | Max results |
offset |
int | Pagination offset |
Export log collection data.
Query Parameters:
| Parameter | Type | Default | Options |
|---|---|---|---|
format |
string | json |
json, csv, txt, zip |
Analyze a log collection for patterns and insights.
Success Response (200):
{
"collection_id": 5,
"total_entries": 5000,
"entries_by_level": {"error": 100, "warning": 500, "info": 3000, "debug": 1400},
"entries_by_component": {"api": 2000, "storage": 1500, "media_processor": 1500},
"error_patterns": {"connection_timeout": 45, "file_not_found": 30},
"time_range": {"start": "2024-01-20T00:00:00Z", "end": "2024-01-20T23:59:59Z"},
"insights": ["Error rate increased 40% between 14:00-16:00", "Storage component shows timeout pattern"]
}Create a shareable link for a log collection.
Request Body:
{
"collection_id": 5,
"share_type": "private",
"expires_at": "2024-02-01T00:00:00Z",
"permissions": ["read"],
"recipients": ["dev@example.com"]
}Access a shared log collection via share token.
Revoke a log share.
Stream live logs via Server-Sent Events (SSE).
| Property | Value |
|---|---|
| Content-Type | text/event-stream |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
string | Filter by level |
component |
string | Filter by component |
search |
string | Search term |
SSE Format:
data: {"id":1,"timestamp":"2024-01-20T10:00:00Z","level":"error","component":"api","message":"Request timeout","context":{}}
data: {"id":2,"timestamp":"2024-01-20T10:00:01Z","level":"info","component":"storage","message":"File scan completed","context":{"files":500}}
Get log management statistics.
Success Response (200):
{
"total_collections": 25,
"total_entries": 150000,
"active_shares": 3,
"collections_by_status": {"completed": 20, "in_progress": 3, "failed": 2},
"recent_collections": 5
}Simple health check endpoint. No authentication required.
Success Response (200):
{
"status": "healthy",
"time": "2024-01-20T12:00:00Z"
}Prometheus metrics endpoint. Returns metrics in Prometheus exposition format. No authentication required.
Tracked metrics include HTTP request durations, request counts, response sizes, active goroutines, and memory usage.
All requests pass through these middleware layers:
| Middleware | Description |
|---|---|
| CORS | Cross-Origin Resource Sharing headers |
| Prometheus Metrics | Request duration and count tracking |
| Logger | Structured request logging (zap) |
| Error Handler | Consistent error response formatting |
| Request ID | Unique X-Request-ID header per request |
| Input Validation | Request body sanitization and validation |
| JWT Auth | Token validation on /api/v1/* routes (except auth) |
| Rate Limiting | Per-user request throttling |
All error responses follow a consistent format:
{
"error": "Human-readable error message"
}Or the structured format used by subtitle and recommendation handlers:
{
"success": false,
"error": "Human-readable error message",
"code": "MACHINE_READABLE_CODE"
}| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created (user registration, resource creation) |
| 204 | No Content (successful deletion) |
| 400 | Bad Request (validation error, invalid parameters) |
| 401 | Unauthorized (missing or invalid JWT) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found (resource does not exist) |
| 409 | Conflict (duplicate resource) |
| 500 | Internal Server Error |
Rate limiting is applied per-user based on the JWT token.
| Endpoint Group | Limit |
|---|---|
/api/v1/auth/* |
5 requests/minute |
All other /api/v1/* |
100 requests/minute |
When rate limited, the server returns 429 Too Many Requests.