Add AnimeAPI integration to resolve anime database IDs (MAL, AniList, Kitsu, etc.) to TMDB/IMDB/TVDB for MKV tagging. The --enrich flag overrides show title and fills in year when missing from the service. - Add animeapi-py dependency for cross-platform anime ID resolution - Add --animeapi option (e.g. mal:12345, anilist:98765, defaults to MAL) - Add --enrich flag to override title/year from external sources - Remove --tmdb-name and --tmdb-year in favor of unified --enrich - Update REST API params and docs to match
11 KiB
REST API Documentation
The unshackle REST API allows you to control downloads, search services, and manage jobs remotely. Start the server with unshackle serve and access the interactive Swagger UI at http://localhost:8786/api/docs/.
Quick Start
# Start the server (no authentication)
unshackle serve --no-key
# Start with authentication
unshackle serve # Requires api_secret in unshackle.yaml
Authentication
When api_secret is set in unshackle.yaml, all API requests require authentication via:
- Header:
X-API-Key: your-secret-key-here - Query parameter:
?api_key=your-secret-key-here
Use --no-key to disable authentication entirely (not recommended for public-facing servers).
# unshackle.yaml
serve:
api_secret: "your-secret-key-here"
Endpoints
GET /api/health
Health check with version and update information.
curl http://localhost:8786/api/health
{
"status": "ok",
"version": "4.0.0",
"update_check": {
"update_available": false,
"current_version": "4.0.0",
"latest_version": null
}
}
GET /api/services
List all available streaming services.
curl http://localhost:8786/api/services
Returns an array of services with tag, aliases, geofence, title_regex, url, and help text.
POST /api/search
Search for titles from a streaming service.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
service |
string | Service tag (e.g., NF, AMZN, ATV) |
query |
string | Search query |
Optional parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
profile |
string | null |
Profile for credentials/cookies |
proxy |
string | null |
Proxy URI or country code |
no_proxy |
boolean | false |
Disable all proxy use |
curl -X POST http://localhost:8786/api/search \
-H "Content-Type: application/json" \
-d '{"service": "ATV", "query": "hijack"}'
{
"results": [
{
"id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
"title": "Hijack",
"description": null,
"label": "TV Show",
"url": "https://tv.apple.com/us/show/hijack/umc.cmc.1dg08zn0g3zx52hs8npoj5qe3"
}
],
"count": 1
}
POST /api/list-titles
Get available titles (seasons/episodes/movies) for a service and title ID.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
service |
string | Service tag |
title_id |
string | Title ID or URL |
curl -X POST http://localhost:8786/api/list-titles \
-H "Content-Type: application/json" \
-d '{"service": "ATV", "title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3"}'
{
"titles": [
{
"type": "episode",
"name": "Final Call",
"series_title": "Hijack",
"season": 1,
"number": 1,
"year": 2023,
"id": "umc.cmc.4levibvvz01hl4zsm0jdk5v2p"
}
]
}
POST /api/list-tracks
Get video, audio, and subtitle tracks for a title.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
service |
string | Service tag |
title_id |
string | Title ID or URL |
Optional parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
wanted |
array | all | Episode filter (e.g., ["S01E01"]) |
profile |
string | null |
Profile for credentials/cookies |
proxy |
string | null |
Proxy URI or country code |
no_proxy |
boolean | false |
Disable all proxy use |
curl -X POST http://localhost:8786/api/list-tracks \
-H "Content-Type: application/json" \
-d '{
"service": "ATV",
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
"wanted": ["S01E01"]
}'
Returns video, audio, and subtitle tracks with codec, bitrate, resolution, language, and DRM information.
POST /api/download
Start a download job. Returns immediately with a job ID (HTTP 202).
Required parameters:
| Parameter | Type | Description |
|---|---|---|
service |
string | Service tag |
title_id |
string | Title ID or URL |
Quality and codec parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
quality |
array[int] | best | Resolution(s) (e.g., [1080, 2160]) |
vcodec |
string or array | any | Video codec(s): H264, H265/HEVC, VP9, AV1, VC1 |
acodec |
string or array | any | Audio codec(s): AAC, AC3, EC3, AC4, OPUS, FLAC, ALAC, DTS |
vbitrate |
int | highest | Video bitrate in kbps |
abitrate |
int | highest | Audio bitrate in kbps |
range |
array[string] | ["SDR"] |
Color range(s): SDR, HDR10, HDR10+, HLG, DV, HYBRID |
channels |
float | any | Audio channels (e.g., 5.1, 7.1) |
no_atmos |
boolean | false |
Exclude Dolby Atmos tracks |
split_audio |
boolean | null |
Create separate output per audio codec |
sub_format |
string | null |
Output subtitle format: SRT, VTT, ASS, SSA, TTML |
Episode selection:
| Parameter | Type | Default | Description |
|---|---|---|---|
wanted |
array[string] | all | Episodes (e.g., ["S01E01", "S01E02-S01E05"]) |
latest_episode |
boolean | false |
Download only the most recent episode |
Language parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
lang |
array[string] | ["orig"] |
Language for video and audio (orig = original) |
v_lang |
array[string] | [] |
Language override for video tracks only |
a_lang |
array[string] | [] |
Language override for audio tracks only |
s_lang |
array[string] | ["all"] |
Language for subtitles |
require_subs |
array[string] | [] |
Required subtitle languages (skip if missing) |
forced_subs |
boolean | false |
Include forced subtitle tracks |
exact_lang |
boolean | false |
Exact language matching (no variants) |
Track selection:
| Parameter | Type | Default | Description |
|---|---|---|---|
video_only |
boolean | false |
Only download video tracks |
audio_only |
boolean | false |
Only download audio tracks |
subs_only |
boolean | false |
Only download subtitle tracks |
chapters_only |
boolean | false |
Only download chapters |
no_video |
boolean | false |
Skip video tracks |
no_audio |
boolean | false |
Skip audio tracks |
no_subs |
boolean | false |
Skip subtitle tracks |
no_chapters |
boolean | false |
Skip chapters |
audio_description |
boolean | false |
Include audio description tracks |
Output and tagging:
| Parameter | Type | Default | Description |
|---|---|---|---|
tag |
string | null |
Override group tag |
repack |
boolean | false |
Add REPACK tag to filename |
tmdb_id |
int | null |
Use specific TMDB ID for tagging |
imdb_id |
string | null |
Use specific IMDB ID (e.g., tt1375666) |
animeapi_id |
string | null |
Anime database ID via AnimeAPI (e.g., mal:12345) |
enrich |
boolean | false |
Override show title and year from external source |
no_folder |
boolean | false |
Disable folder creation for TV shows |
no_source |
boolean | false |
Remove source tag from filename |
no_mux |
boolean | false |
Do not mux tracks into container |
output_dir |
string | null |
Override output directory |
Download behavior:
| Parameter | Type | Default | Description |
|---|---|---|---|
profile |
string | null |
Profile for credentials/cookies |
proxy |
string | null |
Proxy URI or country code |
no_proxy |
boolean | false |
Disable all proxy use |
workers |
int | null |
Max threads per track download |
downloads |
int | 1 |
Concurrent track downloads |
slow |
boolean | false |
Add 60-120s delay between titles |
best_available |
boolean | false |
Continue if requested quality unavailable |
skip_dl |
boolean | false |
Skip download, only get decryption keys |
export |
string | null |
Export keys to JSON file path |
cdm_only |
boolean | null |
Only use CDM (true) or only vaults (false) |
no_cache |
boolean | false |
Bypass title cache |
reset_cache |
boolean | false |
Clear title cache before fetching |
Example:
curl -X POST http://localhost:8786/api/download \
-H "Content-Type: application/json" \
-d '{
"service": "ATV",
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
"wanted": ["S01E01"],
"quality": [1080, 2160],
"vcodec": ["H265"],
"acodec": ["AAC", "EC3"],
"range": ["HDR10", "SDR"],
"split_audio": true,
"lang": ["en"]
}'
{
"job_id": "504db959-80b0-446c-a764-7924b761d613",
"status": "queued",
"created_time": "2026-02-27T18:00:00.000000"
}
GET /api/download/jobs
List all download jobs with optional filtering and sorting.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
status |
string | all | Filter by status: queued, downloading, completed, failed, cancelled |
service |
string | all | Filter by service tag |
sort_by |
string | created_time |
Sort field: created_time, status, service |
sort_order |
string | desc |
Sort order: asc, desc |
# List all jobs
curl http://localhost:8786/api/download/jobs
# Filter by status
curl "http://localhost:8786/api/download/jobs?status=completed"
# Filter by service
curl "http://localhost:8786/api/download/jobs?service=ATV"
GET /api/download/jobs/{job_id}
Get detailed information about a specific download job including progress, parameters, and error details.
curl http://localhost:8786/api/download/jobs/504db959-80b0-446c-a764-7924b761d613
{
"job_id": "504db959-80b0-446c-a764-7924b761d613",
"status": "completed",
"created_time": "2026-02-27T18:00:00.000000",
"service": "ATV",
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
"progress": 100.0,
"parameters": { ... },
"started_time": "2026-02-27T18:00:01.000000",
"completed_time": "2026-02-27T18:00:15.000000",
"output_files": [],
"error_message": null,
"error_details": null
}
DELETE /api/download/jobs/{job_id}
Cancel a queued or running download job.
curl -X DELETE http://localhost:8786/api/download/jobs/504db959-80b0-446c-a764-7924b761d613
Returns confirmation on success, or an error if the job has already completed or been cancelled.
Error Responses
All endpoints return consistent error responses:
{
"status": "error",
"error_code": "INVALID_PARAMETERS",
"message": "Invalid vcodec: XYZ. Must be one of: H264, H265, VP9, AV1, VC1, VP8",
"timestamp": "2026-02-27T18:00:00.000000+00:00",
"details": { ... }
}
Common error codes:
INVALID_INPUT- Malformed request bodyINVALID_PARAMETERS- Invalid parameter valuesMISSING_SERVICE- Service tag not providedINVALID_SERVICE- Service not foundSERVICE_ERROR- Service initialization or runtime errorAUTH_FAILED- Authentication failureNOT_FOUND- Job or resource not foundINTERNAL_ERROR- Unexpected server error
When --debug-api is enabled, error responses include additional debug_info with tracebacks and stderr output.
Download Job Lifecycle
queued -> downloading -> completed
\-> failed
queued -> cancelled
downloading -> cancelled
Jobs are retained for 24 hours after completion. The server supports up to 2 concurrent downloads by default.