-
Notifications
You must be signed in to change notification settings - Fork 0
Developer API
CHUB exposes a REST API so you can automate from scripts. Everything lives under /api/*. Every authenticated endpoint requires a JWT in Authorization: Bearer <token>; server-sent-event streams accept ?token=<jwt> as a fallback because browsers can't set headers on EventSource.
This page covers the endpoints most users reach for. For the complete list, visit the live OpenAPI docs at http://<your-host>:8000/docs once CHUB is running — FastAPI generates them from the source and they're always in sync.
Base URL: http://<host>:8000. Request bodies are JSON. Errors come back as {"detail": "message"} with conventional HTTP status codes. Timestamps are ISO-8601 UTC unless noted. Endpoints that paginate accept limit and offset query parameters.
-
GET /api/auth/status— returns{"configured": true|false}. Unauthenticated. -
POST /api/auth/setup— first-run only; body{ "username": "...", "password": "..." }; returns{ "username": "...", "token": "<jwt>" }. Rejected if an admin already exists. -
POST /api/auth/login— body{ "username": "...", "password": "..." }; returns{ "token": "<jwt>", "expires_at": "..." }. Rate-limited: roughly one attempt every 5 seconds with a burst of 5; exceed it and you'll get429.
-
GET /api/modules— list every module with its enabled flag, last run, and current status. -
GET /api/modules/run-states— snapshot of every module's run state (idle / running / queued / error). -
GET /api/modules/events— server-sent event stream; emits a JSON payload whenever a module's run state changes. Auth via?token=<jwt>. The frontend auto-reconnects. -
GET /api/modules/{name}— full state for one module: config, last run, current run (if any), schedule. -
GET /api/modules/{name}/schema— JSON schema for the module's config, used to render settings forms. -
PUT /api/modules/{name}/config— replace the module's config block; validated before persisting. -
POST /api/modules/{name}/execute— queue a manual run. Returns{"job_id": ...}. Body can carry one-shot overrides. -
GET /api/modules/{name}/status/{job_id}— live status of a queued/running job. -
DELETE /api/modules/{name}/execution/{job_id}— request cooperative cancellation. The job's cancel event is set; 11 of the 13 modules check the event and exit cleanly on the next iteration. Exceptions:border_replacerrruns to completion (no checks).plex_maintenanceis partial: its PhotoTranscoder cleanup stops; the three Plex-API tasks (empty_trash,clean_bundles,optimize_db) run to completion. -
GET /api/modules/{name}/history?limit=25— recent runs. -
POST /api/modules/{name}/test— connectivity test for modules that need external services.
-
GET /api/media/search?type=movie&limit=50&offset=0— unified search across every configured Radarr/Sonarr/Lidarr. Supportstype,status,tag,sort,order. -
GET /api/media/stats?period=30d— counters filtered bycreated_at;periodis7d,30d,90d, orall. -
GET /api/media/duplicates?similarity=0.8— duplicate groups.similarity=1.0is exact-title; lower values use fuzzy matching. -
POST /api/media/duplicates/{group_id}/resolve— resolve a duplicate group. Body:{ "keepId": "...", "removeIds": ["..."], "deleteFiles": true, "addImportExclusion": true }. -
GET /api/media/low-rated?max_rating=5.0— items below a rating threshold. -
GET /api/media/incomplete-metadata?fields=rating,studio,language,genre— items missing any of the requested fields. -
POST /api/media/refresh— refresh the media cache from your ARRs. -
POST /api/media/scan— scan for new content. -
POST /api/media/export— export the current filter as a list. -
POST /api/media/fix-metadata— run a bulk metadata fix over the currently filtered set. -
GET /api/media/{media_id}— single media record. -
GET /api/media/{media_id}/poster— proxy the poster image from the item's source ARR instance. API keys stay server-side; SSRF guard blocks cloud-metadata and link-local targets. Response isimage/*withCache-Control: public, max-age=86400. -
PUT /api/media/{media_id}/metadata— inline metadata edit. Writes amedia_edit_historyrow per field changed. -
DELETE /api/media/{media_id}?delete_files=true— remove from the cache and optionally delete files. -
POST /api/media/{media_id}/fix-metadata— fix metadata for a single item. -
GET /api/media/{media_id}/history— audit trail of edits. -
GET /api/media/{media_id}/import-exclusion— query whether this item is on the ARR's import exclusion list. -
GET /api/media/collections— list collections. -
POST /api/media/collections— create a collection. -
PUT /api/media/collections/{collection_id}/DELETE /api/media/collections/{collection_id}— update or remove. -
POST /api/media/collections/from-tag— build a collection from an ARR tag. Body:{ "tag": "favorites", "collection_name": "Favorites 2026" }.
-
GET /api/posters/list?type=movie&limit=100&offset=0— paginated poster index with width/height if backfilled. -
GET /api/posters/search— text search against poster filenames. -
GET /api/posters/browse— directory-style browse of the poster tree. -
GET /api/posters/stats— counts, storage used, orphan report. -
GET /api/posters/duplicates— exact-hash duplicates. -
POST /api/posters/duplicates/{group_id}/resolve— pick which copy to keep. -
GET /api/posters/low-resolution?min_width=1000— posters below a resolution threshold. -
GET /api/posters/added-since?cutoff=2026-01-01T00:00:00Z— posters added since a cutoff. -
POST /api/posters/backfill-dimensions?limit=500— incremental: fills width/height for rows that lack them. -
POST /api/posters/optimize— optimize posters;{ "mode": "report"|"optimize", "max_width": 2000, "format": "webp", "quality": 82, "paths": [...] }. -
POST /api/posters/auto-match— batch-match unmatched posters to media. -
POST /api/posters/upload— upload one or more posters. -
GET /api/posters/sources/gdrive/search— search posters in configured GDrive sources. -
GET /api/posters/sources/assets/search— search posters in your local assets tree. -
GET /api/posters/matched/stats//unmatched/stats//unmatched/details— matched/unmatched reporting. -
GET /api/posters/gdrive/stats/POST /api/posters/gdrive/sync— inspect / trigger a sync. -
GET /api/posters/{poster_id}— single poster record. -
GET /api/posters/{poster_id}/thumbnail?width=200— generate (and cache) a JPEG thumbnail. -
POST /api/posters/{poster_id}/download?size=500&format=webp&quality=80— download the poster resized/re-encoded. -
POST /api/posters/{poster_id}/sync-metadata— sync the poster's metadata from its matched media record. -
DELETE /api/posters/{poster_id}— delete a single poster.
-
GET /api/jobs?status=success&module=jduparr&limit=25&offset=0— filter + paginate. -
GET /api/jobs/stats— counts by status / module over the last 30 days. -
GET /api/jobs/{job_id}— full job record. -
GET /api/jobs/{job_id}/log-tail?bytes=10000— tail of the job's log. -
POST /api/jobs/{job_id}/retry— re-queue a failed job. -
DELETE /api/jobs/old?days=30— purge completed jobs older than N days. -
GET /api/jobs/webhook-origins?days=7— aggregates theoriginmetadata on webhook-sourced jobs.
-
GET /api/schedule— current cron/interval rules per module. -
POST /api/schedule— replace the full schedule dict. -
GET /api/schedule/{module_id}— the current rule for one module. -
DELETE /api/schedule/{module_id}— remove the rule (module becomes manual-only).
-
GET /api/instances— all configured Radarr/Sonarr/Lidarr/Plex instances, secrets redacted. -
GET /api/instances/types/GET /api/instances/types/{instance_type}/schema— discover the schema for a given instance type. -
GET /api/instances/health— most-recent health probe per instance. -
POST /api/instances/test— test a candidate config before saving (body describes the instance). -
POST /api/instances— add an instance. -
GET /api/instances/{instance_id}/PUT /api/instances/{instance_id}/DELETE /api/instances/{instance_id}— CRUD by id. -
PATCH /api/instances/{instance_id}— partial update (e.g. toggle enabled). -
POST /api/instances/{instance_id}/test— force a connectivity test now. -
POST /api/instances/{instance_id}/refresh/POST /api/instances/{instance_id}/sync— kick cache refresh / full sync. -
GET /api/instances/{instance_id}/stats//health//logs— per-instance telemetry. -
GET /api/plex/{instance}/libraries— library sections for a named Plex instance. Returns[{title, type}, …]wheretypeis the authoritative Plex section type (movie,show,artist,photo). The UI usestypeto bucket libraries into Movies / TV Shows / Other so a user-renamed library (e.g. "Cinema" instead of "Movies") still categorizes correctly.
Powers the /poster/border-replacerr preview page. All three endpoints are read-only / non-destructive — they generate side-by-side composites into a temp directory and serve the bytes back; nothing under destination_dir is touched.
-
GET /api/border-replacerr/preview/options— holiday choices for the page's dropdown. Returns[{value, label}, …]— always includesdefault(useborder_colors) andcurrent(run the live holiday resolver) plus one entry per configuredholidays[]. -
POST /api/border-replacerr/preview?count=6&holiday=current— generate fresh composites.countclamps to[1, 24];holidayisdefault,current, or a configured holiday name. Returns apreviewsarray — each entry has{token, title, kind, season_number, color}. The composite for a giventokenis fetched separately. -
GET /api/border-replacerr/preview/file/{token}.jpg— serve the bytes for a token issued by the POST. Tokens are uuid4 hex; anything else returns 404. Files are wiped at the start of each new POST so the temp directory never grows.
-
GET /api/version— CHUB version string. -
GET /api/health— unauthenticated liveness probe used by the container healthcheck; returns{ "status": "ok" }. -
GET /api/directory— walk the filesystem visible to the container (read-only) for path pickers. -
POST /api/folder— create a folder (used by the UI when setting up new destinations). -
POST /api/test— generic connectivity test helper. -
POST /api/backup— creates a zip ofconfig.yml+chub.dband returns the download. -
GET /api/backups— list saved backups on disk. -
POST /api/restore— upload a backup zip to replace config + DB (destructive). -
GET /api/system/health/snapshots?days=7— time-series of scheduler probes. -
GET /api/system/digest?days=7— aggregated activity payload. -
GET /api/system/cleanup-candidates— orphaned posters, errored jobs, unmatched media/collections counts.
-
POST /api/labelarr/sync— sync labels for a single media item or a specific mapping. Body describes what to sync. -
POST /api/labelarr/bulk-sync— bulk version; body:{ "media_ids": ["radarr_main:1", "radarr_main:2", ...] }(cap 1000).
See Webhooks for the full walkthrough. Five endpoints:
POST /api/webhooks/poster/addGET /api/webhooks/unmatched/statusPOST /api/webhooks/unmatched/processGET /api/webhooks/cleanarr/statusPOST /api/webhooks/cleanarr/process
-
GET /api/config— fullconfig.ymlas JSON, secrets replaced by********. -
POST /api/config— write config. Fields still equal to********are kept from the on-disk value, so editing non-sensitive fields doesn't wipe your API keys.
-
GET /api/logs— list log files grouped by module. -
GET /api/logs/{module_name}?bytes=50000— tail of the module's latest log. -
GET /api/logs/{module}/{filename}— plain-text serve of a specific rotated log file.
-
GET /api/notifications— current notifications config (per module +main). -
POST /api/notifications— write config. -
GET /api/notifications/{module_id}— per-module notification config. -
POST /api/notifications/test— send a test notification. -
DELETE /api/notifications/{module_id}/{service_type}— remove one notification target.
-
GET /api/nestarr/scan/GET /api/nestarr/results— scan for nested-media issues. -
POST /api/nestarr/preview/POST /api/nestarr/fix— preview / apply fixes.