Skip to content

Requests

HTTP routes and behavior for requests.

GET /api/me/request-quotas # user: effective rules, usage, remaining units, replenishment times
POST /api/requests/preview # user: same selection as create; cost/fits/seasons, reserves nothing
GET|PUT /api/admin/request-quotas # admin: User defaults {allowances:[{media_type,book_format?,count,window_days}]}
GET|PUT /api/admin/users/{userID}/request-quotas # admin: effective usage / complete overrides; inherit:true clears a rule
POST /api/admin/users/{userID}/request-quotas/reset # admin: {allowances:[{media_type,book_format?}]} audited reset
GET /api/requests/delivery-status # book/music by media_type + instance_id and foreign_id or catalog_provider + catalog_id; all media by request_id (admins can inspect saved intent after instance removal, with live state unknown)
POST /api/requests/{id}/delivery # requester/admin: {action: retry|cancel, book_format?}; retired confirm returns 410
POST /api/requests # user: create (movie/tv by tmdb_id; books by foreign_id +
# book_format; music by foreign_id; the MusicBrainz
# release-group id; optional instance_id for every media
# type; see the library-selection notes). A kids account
# asking for a movie/show outside its limits gets 404
# "not available" (503 when the limit could not be checked)
GET /api/requests # user: own request history (a kids account's hidden
# movie/show rows are left out)
GET /api/requests/options # user: what this user may choose (seasons, quality);
# optional instance_id scopes quality profiles to that library
GET /api/requests/book-status # user: per-format live state by foreign_id; optional instance_id, title, q (exact lookup context)
GET /api/requests/book-library # user: title/format digest with typed identity_keys and complete author summaries
# (name/position) and author (name + the library's own
# author_foreign_id); optional instance_id (brief cache)
GET /api/requests/book-recent # user: newest book-file imports; optional instance_id, limit (cached)
GET /api/requests/book-authors # user: the library's authors with per-title counts;
# optional instance_id (cached), sort=books|name|added
# (default books; unknown values fall back, never 400)
GET /api/requests/book-author # user: one author by foreign_id + every title of theirs the
# library tracks, with per-format ownership; optional
# instance_id. 404 when that library holds no such author
GET /api/requests/book-series # user: the series the library holds books of, with
# per-title counts; optional instance_id (cached),
# sort=books|name (default books)
GET /api/requests/book-series-detail # user: one series by name + every title of it the library
# tracks, in reading order with per-format ownership;
# optional instance_id. 404 when no such series
GET /api/requests/music-status # user: album state by foreign_id; optional instance_id; include_saved=false reads live availability independently.
# Single status (music has no format axis); carries
# canonical_foreign_id when the library re-keyed the album
GET /api/requests/music-library # user: actual album records, record/artist/group IDs, release_type and status; optional instance_id (brief cache)
GET /api/requests/music-saved # user: saved music receipts for the authorized instance; no provider calls
GET /api/requests/music-recent # user: newest music imports; optional instance_id, limit (cached)
GET /api/requests/music-artists # user: the library's artists with per-album counts;
# optional instance_id (cached), sort=albums|name|added
# (default albums; unknown values fall back, never 400)
GET /api/requests/music-artist # user: one artist by foreign_id + every album of theirs the
# library tracks, with ownership; optional instance_id.
# 404 when that library holds no such artist
GET /api/requests/{tmdb_id}/status # user: live availability + download progress; optional include_instance_statuses=false skips sibling-library reads
# movies already in the library also carry releases
# {in_cinemas, digital} as YYYY-MM-DD calendar dates.
# Optional instance_id scopes the read to that granted
# library; a user granted >1 library for the media type
# also gets instance_statuses {id: {status}} chips
# (TV: live, season-scoped, with status_known;
# movies: digest-grade, brief cache)
GET /api/admin/requests # admin: pending approval queue; rows carry the book's
# foreign_id, a best-effort TMDB poster_path (movie/tv),
# and add_failure_reason when the row is not a policy
# question but an add that already ran and failed
GET /api/admin/requests/waiting # admin: pending rows the SERVER owns and retries itself
# (park_reason set); same row shape plus wait_reason and
# last_attempt_at and delivery. Recovery actions use /requests/{id}/delivery;
# never counted by the badge or request_pending push
POST /api/admin/requests/{id}/approve # admin: approve all media for durable delivery; TV scope additions charge the original requester atomically
POST /api/admin/requests/{id}/deny # admin: deny with optional reason
POST /api/admin/requests/{id}/wait # admin: "try again" on an ended author-import wait; replay the add and resume the watch
GET|PUT /api/admin/request-settings # admin: global policy (require_approval,
# allow_season_choice, default scope/quality...)
GET|PUT /api/admin/users/{userID}/request-settings # admin: per-user overrides
GET /api/admin/tv-matches # admin: bundled/custom/paused matches and revisions
GET /api/admin/tv-matches/candidates # admin: q=title or TVDB ID; optional instance_id
GET /api/admin/tv-matches/{tmdb_id} # admin: resolved match + source/target seasons; optional instance_id
PUT /api/admin/tv-matches/{tmdb_id} # admin: {revision, mode: custom|paused|default, instance_id?, tvdb_id?, season_map?}
DELETE /api/admin/tv-matches/{tmdb_id} # admin: restore default with {revision, instance_id?}
GET /api/admin/tv-matches/{tmdb_id}/repairs # admin: latest 200 accepted original requests, affected targets/scopes
POST /api/admin/requests/{id}/repair-tv-match # admin: {revision} from preview; idempotent linked corrective request

Request statuses: unavailable, requested, pending (awaiting approval), denied, downloading, partial, available.

TV responses add optional match (resolved TVDB identity, source-to-target season_map, provenance, revision, state, message, library series_id) and delivery data. status_known:false distinguishes an unresolved match or failed library read from confirmed absence; clients must not enable requests until a known result. Each TV instance_statuses entry has its own status_known. Catalog cards can pass include_instance_statuses=false to read only their selected/default library using the same authorization, content policy, source-season projection and saved-request overlay as details. Omitting the parameter retains sibling-library statuses. The /api/config capability tv_match_corrections:true enables corrected catalog badges for all users and correction controls for admins without changing compatibility floors. Delivery reads by request_id support TV snapshots; foreign-ID delivery-status reads remain book/music-only.

Book intake accepts the existing native foreign_id, title, book_format, optional instance_id, and search_term. Saving performs no Chaptarr reads or writes: it persists the original identity, instance, title, search term, approval requirement, and one job per format, wakes the durable worker, and returns the saved response. request_id, catalog_ref, delivery, and existing response fields remain compatible. New book catalog_ref submissions return HTTP 410 with structured catalog_retired, a message and /dashboard/books search action without contacting Open Library. Music retains native and MusicBrainz source-based requests.

Delivery states are approval, queued, processing, retry, waiting_library, attention, complete, and cancelled; old needs_match jobs migrate to attention with catalog_retired. Approval is independent of dispatch. Worker and per-instance leases serialize writes, expire after five minutes, and renew while active. Every attempt reauthorizes the original requester and reads current service state; Chaptarr mutations recheck authorization immediately before each write. Completed formats are checkpointed. Unknown POST outcomes reconcile against the library and native import receipts before replay. Retry delays begin at one minute, double up to six hours, honor longer Retry-After, and become attention after 50 attempts. Retry accepts an optional concrete book_format; retry and cancellation cannot bypass approval or select another instance.

An active Chaptarr author import uses waiting_library and park_reason='author_import'. The native import is observed on the five-minute sweep and webhook, without repeatedly adding it or imposing a time-based give-up. Terminal or ambiguous native import outcomes become attention; older Chaptarr without this API retains the add-probe compatibility path. Legacy requests keep their original approval/import gate when revisited.

book_format_waits explains pending delivery per format alongside the existing requested compatibility status. Availability is read live with the existing short TTL and webhook invalidation; it outranks wait text, and a failed live read returns status_known:false. A completed delivery is not proof a file still exists. The admin Saved requests list carries recovery actions and remains outside the approval badge and approval-needed pushes. request_updated refreshes the requester and book subscribers without claiming an approval decision. Cancelling a personal subscription preserves other subscribers and their requested formats; admins can cancel shared work. Completed service work is not undone by cancellation.

search_books searches the selected Chaptarr instance and returns native identities, instance IDs, and the original search term. Legacy catalog:all uses native search; catalog:public, source-based book display_media / request_media, and retired confirmation actions return structured catalog_retired. search_music retains catalog:all|public|library, paging, and instance_id. request_media accepts request_id with retry/cancel actions; check_request_status can read a saved request by ID without live work. No MCP tools or credentials were added.

View the maintained source for this page.