Skip to content

Seerr-compatible API (`X-Api-Key`, no session)

HTTP routes and behavior for seerr-compatible api (`x-api-key`, no session).

GET /api/v1/status # { version, commitTag, updateAvailable, commitsBehind }
GET /api/v1/settings/about # { version, totalRequests, totalMediaItems, tz } -- the connection test integrators run
GET /api/v1/settings/jobs # [ the availability-sync job ]
POST /api/v1/settings/jobs/availability-sync/run # drop the cached Radarr/Sonarr digests so the next read is fresh; other job ids 404
GET /api/v1/request?take&skip&filter&mediaType&requestedBy&sort&sortDirection # { pageInfo, results: [MediaRequest] }
GET /api/v1/request/count # { total, movie, tv, pending, approved, declined, processing, available, completed }
GET /api/v1/request/{id} # one MediaRequest
DELETE /api/v1/request/{id} # forget the request (204; 404 for an unknown or non-movie/TV id; 409 while its delivery is being written)
POST /api/v1/request/{id}/approve | /decline # decide as the issuing admin; answers the request as it now reads
GET /api/v1/movie/{tmdbId} # TMDB details + mediaInfo (the title's Media record with its requests, oldest first)
GET /api/v1/tv/{tmdbId} # same for a series, with TMDB seasons and per-season media status
GET /api/v1/tv/{tmdbId}/season/{n} # TMDB season with episode air dates
DELETE /api/v1/media/{mediaId} # forget every request of the title (204, also for an unknown id)
GET /api/v1/user?take&skip | /user/{id} # Seerr-shaped users with their linked media-server identities

Cantinarr’s request ledger in the shape of the Seerr v1 API (the merged Overseerr/Jellyseerr project), so tools written against Seerr read Cantinarr without changes. The surface is what those integrators actually call, verified against their source (Maintainerr’s rule getter, collection handler and its own fake-seerr mock; Dashbrr’s request panel; Homepage’s request/count widget), not the whole Seerr API; anything else under /api/v1 is a 404 with Seerr’s { message } error body, which every error here uses. Authentication is Seerr’s: the X-Api-Key header must carry the issued key (above), and every call acts as the administrator who issued it. That makes this an admin surface: kids-account filtering does not apply, no user session can reach it, and the key is the only credential it accepts.

Requests are the request_log rows for movies and TV, newest first (Seerr’s default sort; sort=modified and sortDirection=asc are honoured). Books and music have no Seerr type and stay out, including from deletion: an integrator that only ever saw movie/TV ids cannot remove a book or album request. requestedBy carries the identity the media server knows, which is what Maintainerr joins against its watch history: plexUsername/plexId from the Plex sign-in identity or an accepted Plex share, jellyfinUsername/jellyfinUserId from a linked Jellyfin or Emby account (Seerr files Emby under the Jellyfin fields), username for everyone, and userType by that precedence (Plex, Jellyfin, Emby, local). permissions is Seerr’s bitmask reduced to admin (2) or request (32).

Status is live, never stored, through the same per-instance Radarr/Sonarr digests the request history uses (120 s cache), read once per library per call and taking the best answer across every library of that kind. media.status is Seerr’s: available (5), partially available (4), processing (3) for a title a library holds without files, unknown (1) for one no library holds. request.status follows Seerr’s lifecycle: pending (1) and declined (3) as decided; approved (2); completed (5) once the title, or for TV every requested season, is on disk; failed (4) for an approved row whose automatic add failed and never landed. TV seasons[] are the seasons the request covers in the library’s numbering (the target snapshot, so they match what the media server shows; explicit selections directly; a coarse legacy scope resolved against the live series), each with its own status. media.id is derived from the identity Cantinarr has (tmdbId * 2, plus one for TV) so DELETE /media/{id} needs no lookup and can never be confused with the TMDB id. media.updatedAt is the request’s decision time (the approval date Maintainerr reads), mediaAddedAt the movie file’s import date from Radarr (null for TV), is4k always false, serverId 0.

A library that cannot be read is a 503, never a thinner ledger that looks complete: Maintainerr and its kin treat that as transient and protect their items, which is the right outcome; a TV-only read never touches Radarr and still answers. Availability sync is a real no-op with one real effect: Cantinarr already computes availability live, so a title Maintainerr deleted reads unavailable and re-requestable at once, and running the job drops the cached digests so the next read does not wait out the cache window. Deleting a request forgets it for the requester too and releases the allowance it used under the same delivery-aware refund rule every cancel applies; a request whose delivery is being written that moment is refused with 409 rather than pulled out from under the worker.

View the maintained source for this page.