25 KiB
API Documentation
Document Purpose
This document provides comprehensive REST API and WebSocket reference for the Aniworld application.
Source: src/server/fastapi_app.py
1. API Overview
Base URL and Versioning
| Environment | Base URL |
|---|---|
| Local Development | http://127.0.0.1:8000 |
| API Documentation | http://127.0.0.1:8000/api/docs |
| ReDoc Documentation | http://127.0.0.1:8000/api/redoc |
The API does not use versioning prefixes. All endpoints are available under /api/*.
Source: src/server/fastapi_app.py
Authentication
The API uses JWT Bearer Token authentication.
Header Format:
Authorization: Bearer <jwt_token>
Public Endpoints (no authentication required):
/api/auth/*- Authentication endpoints/api/health- Health check endpoints/api/docs,/api/redoc- API documentation/static/*- Static files/,/login,/setup,/queue- UI pages
Source: src/server/middleware/auth.py
Content Types
| Direction | Content-Type |
|---|---|
| Request | application/json |
| Response | application/json |
| WebSocket | application/json (messages) |
Common Headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes* | Bearer token for protected endpoints |
Content-Type |
Yes | application/json for POST/PUT |
Origin |
No | Required for CORS preflight |
*Not required for public endpoints listed above.
2. Authentication Endpoints
Prefix: /api/auth
Source: src/server/api/auth.py
POST /api/auth/setup
Initial setup endpoint to configure the master password. Can only be called once.
Request Body:
{
"master_password": "string (min 8 chars, mixed case, number, special char)",
"anime_directory": "string (optional, path to anime folder)"
}
Response (201 Created):
{
"status": "ok"
}
Errors:
400 Bad Request- Master password already configured or invalid password
Source: src/server/api/auth.py
POST /api/auth/login
Validate master password and return JWT token.
Request Body:
{
"password": "string",
"remember": false
}
Response (200 OK):
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_at": "2025-12-14T10:30:00Z"
}
Errors:
401 Unauthorized- Invalid credentials429 Too Many Requests- Account locked due to failed attempts
Source: src/server/api/auth.py
POST /api/auth/logout
Logout by revoking token.
Response (200 OK):
{
"status": "ok",
"message": "Logged out successfully"
}
Source: src/server/api/auth.py
GET /api/auth/status
Return whether master password is configured and if caller is authenticated.
Response (200 OK):
{
"configured": true,
"authenticated": true
}
Source: src/server/api/auth.py
3. Anime Endpoints
Prefix: /api/anime
Source: src/server/api/anime.py
Series Identifier Convention
The API uses two identifier fields:
| Field | Purpose | Example |
|---|---|---|
key |
Primary identifier - provider-assigned, URL-safe | "attack-on-titan" |
folder |
Metadata only - filesystem folder name | "Attack on Titan (2013)" |
Use key for all API operations. The folder field is for display purposes only.
GET /api/anime/status
Get anime library status information.
Authentication: Required
Response (200 OK):
{
"directory": "/path/to/anime",
"series_count": 42
}
Source: src/server/api/anime.py
GET /api/anime
List library series that have missing episodes.
Authentication: Required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number (must be positive) |
per_page |
int | 20 | Items per page (max 1000) |
sort_by |
string | null | Sort field: title, id, name, missing_episodes |
filter |
string | null | Filter term |
Response (200 OK):
[
{
"key": "beheneko-the-elf-girls-cat",
"name": "Beheneko",
"site": "aniworld.to",
"folder": "beheneko the elf girls cat (2025)",
"missing_episodes": { "1": [1, 2, 3, 4] },
"link": ""
}
]
Source: src/server/api/anime.py
GET /api/anime/search
Search the provider for anime series matching a query.
Authentication: Not required
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | Yes | Search term (max 200 chars) |
Response (200 OK):
[
{
"key": "attack-on-titan",
"name": "Attack on Titan",
"site": "aniworld.to",
"folder": "Attack on Titan (2013)",
"missing_episodes": {},
"link": "https://aniworld.to/anime/stream/attack-on-titan"
}
]
Source: src/server/api/anime.py
POST /api/anime/search
Search via POST body.
Request Body:
{
"query": "attack on titan"
}
Response: Same as GET /api/anime/search
Source: src/server/api/anime.py
POST /api/anime/add
Add a new series to the library with automatic database persistence, folder creation, and episode scanning.
Authentication: Required
Request Body:
{
"link": "https://aniworld.to/anime/stream/attack-on-titan",
"name": "Attack on Titan"
}
Response (200 OK):
{
"status": "success",
"message": "Successfully added series: Attack on Titan",
"key": "attack-on-titan",
"folder": "Attack on Titan",
"db_id": 1,
"missing_episodes": ["1-1", "1-2", "1-3"],
"total_missing": 3
}
Enhanced Flow:
- Validates the request (link format, name)
- Creates Serie object with sanitized folder name
- Saves to database via AnimeDBService
- Creates folder using sanitized display name (not internal key)
- Performs targeted episode scan for this anime only
- Returns response with missing episodes count
Folder Name Sanitization:
- Removes invalid filesystem characters:
< > : " / \ | ? * - Trims leading/trailing whitespace and dots
- Preserves Unicode characters (for Japanese titles)
- Example:
"Attack on Titan: Final Season"→"Attack on Titan Final Season"
Source: src/server/api/anime.py
POST /api/anime/rescan
Trigger a rescan of the local library.
Authentication: Required
Response (200 OK):
{
"success": true,
"message": "Rescan started successfully"
}
Source: src/server/api/anime.py
GET /api/anime/{anime_id}
Return detailed information about a specific series.
Authentication: Not required
Path Parameters:
| Parameter | Description |
|---|---|
anime_id |
Series key (primary) or folder (deprecated fallback) |
Response (200 OK):
{
"key": "attack-on-titan",
"title": "Attack on Titan",
"folder": "Attack on Titan (2013)",
"episodes": ["1-1", "1-2", "1-3"],
"description": null
}
Source: src/server/api/anime.py
4. Download Queue Endpoints
Prefix: /api/queue
Source: src/server/api/download.py
GET /api/queue/status
Get current download queue status and statistics.
Authentication: Required
Response (200 OK):
{
"status": {
"is_running": false,
"is_paused": false,
"active_downloads": [],
"pending_queue": [],
"completed_downloads": [],
"failed_downloads": []
},
"statistics": {
"total_items": 5,
"pending_count": 3,
"active_count": 1,
"completed_count": 1,
"failed_count": 0,
"total_downloaded_mb": 1024.5,
"average_speed_mbps": 2.5,
"estimated_time_remaining": 3600
}
}
Source: src/server/api/download.py
POST /api/queue/add
Add episodes to the download queue.
Authentication: Required
Request Body:
{
"serie_id": "attack-on-titan",
"serie_folder": "Attack on Titan (2013)",
"serie_name": "Attack on Titan",
"episodes": [
{ "season": 1, "episode": 1, "title": "Episode 1" },
{ "season": 1, "episode": 2, "title": "Episode 2" }
],
"priority": "NORMAL"
}
Priority Values: LOW, NORMAL, HIGH
Response (201 Created):
{
"status": "success",
"message": "Added 2 episode(s) to download queue",
"added_items": ["uuid1", "uuid2"],
"item_ids": ["uuid1", "uuid2"],
"failed_items": []
}
Source: src/server/api/download.py
POST /api/queue/start
Start automatic queue processing.
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Queue processing started"
}
Source: src/server/api/download.py
POST /api/queue/stop
Stop processing new downloads from queue.
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Queue processing stopped (current download will continue)"
}
Source: src/server/api/download.py
POST /api/queue/pause
Pause queue processing (alias for stop).
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Queue processing paused"
}
Source: src/server/api/download.py
DELETE /api/queue/{item_id}
Remove a specific item from the download queue.
Authentication: Required
Path Parameters:
| Parameter | Description |
|---|---|
item_id |
Download item UUID |
Response (204 No Content)
Source: src/server/api/download.py
DELETE /api/queue
Remove multiple items from the download queue.
Authentication: Required
Request Body:
{
"item_ids": ["uuid1", "uuid2"]
}
Response (204 No Content)
Source: src/server/api/download.py
DELETE /api/queue/completed
Clear completed downloads from history.
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Cleared 5 completed item(s)",
"count": 5
}
Source: src/server/api/download.py
DELETE /api/queue/failed
Clear failed downloads from history.
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Cleared 2 failed item(s)",
"count": 2
}
Source: src/server/api/download.py
DELETE /api/queue/pending
Clear all pending downloads from the queue.
Authentication: Required
Response (200 OK):
{
"status": "success",
"message": "Removed 10 pending item(s)",
"count": 10
}
Source: src/server/api/download.py
POST /api/queue/reorder
Reorder items in the pending queue.
Authentication: Required
Request Body:
{
"item_ids": ["uuid3", "uuid1", "uuid2"]
}
Response (200 OK):
{
"status": "success",
"message": "Queue reordered with 3 items"
}
Source: src/server/api/download.py
POST /api/queue/retry
Retry failed downloads.
Authentication: Required
Request Body:
{
"item_ids": ["uuid1", "uuid2"]
}
Pass empty item_ids array to retry all failed items.
Response (200 OK):
{
"status": "success",
"message": "Retrying 2 failed item(s)",
"retried_count": 2,
"retried_ids": ["uuid1", "uuid2"]
}
Source: src/server/api/download.py
5. Configuration Endpoints
Prefix: /api/config
Source: src/server/api/config.py
GET /api/config
Return current application configuration.
Authentication: Required
Response (200 OK):
{
"name": "Aniworld",
"data_dir": "data",
"scheduler": {
"enabled": true,
"interval_minutes": 60
},
"logging": {
"level": "INFO",
"file": null,
"max_bytes": null,
"backup_count": 3
},
"backup": {
"enabled": false,
"path": "data/backups",
"keep_days": 30
},
"other": {}
}
Source: src/server/api/config.py
PUT /api/config
Apply an update to the configuration.
Authentication: Required
Request Body:
{
"scheduler": {
"enabled": true,
"interval_minutes": 30
},
"logging": {
"level": "DEBUG"
}
}
Response (200 OK): Updated configuration object
Source: src/server/api/config.py
POST /api/config/validate
Validate a configuration without applying it.
Authentication: Required
Request Body: Full AppConfig object
Response (200 OK):
{
"valid": true,
"errors": []
}
Source: src/server/api/config.py
GET /api/config/backups
List all available configuration backups.
Authentication: Required
Response (200 OK):
[
{
"name": "config_backup_20251213_090130.json",
"size": 1024,
"created": "2025-12-13T09:01:30Z"
}
]
Source: src/server/api/config.py
POST /api/config/backups
Create a backup of the current configuration.
Authentication: Required
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | No | Custom backup name |
Response (200 OK):
{
"name": "config_backup_20251213_090130.json",
"message": "Backup created successfully"
}
Source: src/server/api/config.py
POST /api/config/backups/{backup_name}/restore
Restore configuration from a backup.
Authentication: Required
Response (200 OK): Restored configuration object
Source: src/server/api/config.py
DELETE /api/config/backups/{backup_name}
Delete a configuration backup.
Authentication: Required
Response (200 OK):
{
"message": "Backup 'config_backup_20251213.json' deleted successfully"
}
Source: src/server/api/config.py
POST /api/config/directory
Update anime directory configuration.
Authentication: Required
Request Body:
{
"directory": "/path/to/anime"
}
Response (200 OK):
{
"message": "Anime directory updated successfully",
"synced_series": 15
}
Source: src/server/api/config.py
6. Scheduler Endpoints
Prefix: /api/scheduler
Source: src/server/api/scheduler.py
GET /api/scheduler/config
Get current scheduler configuration.
Authentication: Required
Response (200 OK):
{
"enabled": true,
"interval_minutes": 60
}
Source: src/server/api/scheduler.py
POST /api/scheduler/config
Update scheduler configuration.
Authentication: Required
Request Body:
{
"enabled": true,
"interval_minutes": 30
}
Response (200 OK): Updated scheduler configuration
Source: src/server/api/scheduler.py
POST /api/scheduler/trigger-rescan
Manually trigger a library rescan.
Authentication: Required
Response (200 OK):
{
"success": true,
"message": "Rescan started successfully"
}
Source: src/server/api/scheduler.py
7. Health Check Endpoints
Prefix: /health
Source: src/server/api/health.py
GET /health
Basic health check endpoint.
Authentication: Not required
Response (200 OK):
{
"status": "healthy",
"timestamp": "2025-12-13T10:30:00.000Z",
"version": "1.0.0"
}
Source: src/server/api/health.py
GET /health/detailed
Comprehensive health check with database, filesystem, and system metrics.
Authentication: Not required
Response (200 OK):
{
"status": "healthy",
"timestamp": "2025-12-13T10:30:00.000Z",
"version": "1.0.0",
"dependencies": {
"database": {
"status": "healthy",
"connection_time_ms": 1.5,
"message": "Database connection successful"
},
"filesystem": {
"status": "healthy",
"data_dir_writable": true,
"logs_dir_writable": true
},
"system": {
"cpu_percent": 25.0,
"memory_percent": 45.0,
"memory_available_mb": 8192.0,
"disk_percent": 60.0,
"disk_free_mb": 102400.0,
"uptime_seconds": 86400.0
}
},
"startup_time": "2025-12-13T08:00:00.000Z"
}
Source: src/server/api/health.py
8. WebSocket Protocol
Endpoint: /ws/connect
Source: src/server/api/websocket.py
Connection
URL: ws://127.0.0.1:8000/ws/connect
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
token |
No | JWT token for authenticated access |
Message Types
| Type | Direction | Description |
|---|---|---|
connected |
Server -> Client | Connection confirmation |
ping |
Client -> Server | Keepalive request |
pong |
Server -> Client | Keepalive response |
download_progress |
Server -> Client | Download progress update |
download_complete |
Server -> Client | Download completed |
download_failed |
Server -> Client | Download failed |
download_added |
Server -> Client | Item added to queue |
download_removed |
Server -> Client | Item removed from queue |
queue_status |
Server -> Client | Queue status update |
queue_started |
Server -> Client | Queue processing started |
queue_stopped |
Server -> Client | Queue processing stopped |
scan_progress |
Server -> Client | Library scan progress |
scan_complete |
Server -> Client | Library scan completed |
system_info |
Server -> Client | System information message |
error |
Server -> Client | Error message |
Source: src/server/models/websocket.py
Room Subscriptions
Clients can join/leave rooms to receive specific updates.
Join Room:
{
"action": "join",
"data": { "room": "downloads" }
}
Leave Room:
{
"action": "leave",
"data": { "room": "downloads" }
}
Available Rooms:
downloads- Download progress and status updates
Server Message Format
{
"type": "download_progress",
"timestamp": "2025-12-13T10:30:00.000Z",
"data": {
"download_id": "uuid-here",
"key": "attack-on-titan",
"folder": "Attack on Titan (2013)",
"percent": 45.2,
"speed_mbps": 2.5,
"eta_seconds": 180
}
}
WebSocket Status Endpoint
GET /ws/status
Returns WebSocket service status.
Response (200 OK):
{
"status": "operational",
"active_connections": 5,
"supported_message_types": [
"download_progress",
"download_complete",
"download_failed",
"queue_status",
"connected",
"ping",
"pong",
"error"
]
}
Source: src/server/api/websocket.py
9. Data Models
Download Item
{
"id": "uuid-string",
"serie_id": "attack-on-titan",
"serie_folder": "Attack on Titan (2013)",
"serie_name": "Attack on Titan",
"episode": {
"season": 1,
"episode": 1,
"title": "To You, in 2000 Years"
},
"status": "pending",
"priority": "NORMAL",
"added_at": "2025-12-13T10:00:00Z",
"started_at": null,
"completed_at": null,
"progress": null,
"error": null,
"retry_count": 0,
"source_url": null
}
Status Values: pending, downloading, paused, completed, failed, cancelled
Priority Values: LOW, NORMAL, HIGH
Source: src/server/models/download.py
Episode Identifier
{
"season": 1,
"episode": 1,
"title": "Episode Title"
}
Source: src/server/models/download.py
Download Progress
{
"percent": 45.2,
"downloaded_mb": 256.0,
"total_mb": 512.0,
"speed_mbps": 2.5,
"eta_seconds": 180
}
Source: src/server/models/download.py
10. Error Handling
HTTP Status Codes
| Code | Meaning | When Used |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | Resource created |
| 204 | No Content | Successful deletion |
| 400 | Bad Request | Invalid request body/parameters |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource does not exist |
| 422 | Unprocessable Entity | Validation error |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
Error Response Format
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Human-readable error message",
"details": {
"field": "Additional context"
},
"request_id": "uuid-for-tracking"
}
Source: src/server/middleware/error_handler.py
Common Error Codes
| Error Code | HTTP Status | Description |
|---|---|---|
AUTHENTICATION_ERROR |
401 | Invalid or missing credentials |
AUTHORIZATION_ERROR |
403 | Insufficient permissions |
VALIDATION_ERROR |
422 | Request validation failed |
NOT_FOUND_ERROR |
404 | Resource not found |
CONFLICT_ERROR |
409 | Resource conflict |
RATE_LIMIT_ERROR |
429 | Rate limit exceeded |
11. Rate Limiting
Authentication Endpoints
| Endpoint | Limit | Window |
|---|---|---|
POST /api/auth/login |
5 requests | 60 seconds |
POST /api/auth/setup |
5 requests | 60 seconds |
Source: src/server/middleware/auth.py
Origin-Based Limiting
All endpoints from the same origin are limited to 60 requests per minute per origin.
Source: src/server/middleware/auth.py
Rate Limit Response
{
"detail": "Too many authentication attempts, try again later"
}
HTTP Status: 429 Too Many Requests
12. Pagination
The anime list endpoint supports pagination.
Query Parameters:
| Parameter | Default | Max | Description |
|---|---|---|---|
page |
1 | - | Page number (1-indexed) |
per_page |
20 | 1000 | Items per page |
Example:
GET /api/anime?page=2&per_page=50
Source: src/server/api/anime.py