API Reference - Moonfin-Client/Plugin GitHub Wiki
Every endpoint Moonbase exposes on the server. This page is for developers and for admins debugging an integration. Normal use of Moonfin never needs it.
Paths are absolute and served by both the Jellyfin and Emby plugins unless noted.
Auth column:
- Yes requires any valid Jellyfin or Emby session.
- Admin requires an elevated (administrator) session.
- Session uses a stored Seerr session rather than the platform token.
- No is anonymous (used for web assets, discovery, and the inbound Seerr webhook, which has its own shared secret).
Some areas are gated by config: the Settings and public Themes endpoints return 503 when settings sync is disabled, and the Games endpoints return empty results or 404 when the game library feature is turned off.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Ping |
Yes | Plugin status: version, whether sync is enabled, Seerr/MDBList/TMDB availability, admin defaults, and feature flags so older clients can hide the features they lack. An optional profile query (tv, desktop or mobile) returns defaultSettings with that device's admin defaults layered over the Global ones. messagesSupported is on both servers. recommendationsSupported is Jellyfin only and follows the Use Moonfin Recommends for similar items switch. clientLogSupported is Emby only and follows Enable client log upload. pinSupported, tmdbThumbsSupported, tmdbDetailsSupported, tmdbPersonLinksSupported, tmdbReviewsSupported and extendedCompleteShowingsSupported are on both servers, and incompleteRecordingsSupported follows Detect incomplete recordings
|
| GET | /Moonfin/Defaults |
Yes | The admin-configured default settings profile |
| GET | /Moonfin/Settings |
Yes | The current user's full settings envelope |
| POST | /Moonfin/Settings |
Yes | Save the current user's settings (merge or replace via body) |
| DELETE | /Moonfin/Settings |
Yes | Delete all of the current user's settings |
| HEAD | /Moonfin/Settings |
Yes | Check whether the current user has stored settings (200 or 404) |
| GET | /Moonfin/Settings/Stream |
Yes | Server-sent events stream of settings changes, theme changes, and admin messages. On Emby it answers { "supported": false, "transport": "websocket" } and the same events ride the session websocket instead |
| GET, POST | /Moonfin/Settings/{userId} |
Admin | Get or save another user's settings |
| GET | /Moonfin/Settings/Resolved/{profile} |
Yes | The resolved flat values for a profile (global, desktop, mobile, tv) |
| POST, DELETE | /Moonfin/Settings/Profile/{profile} |
Yes | Save or delete one device profile's overrides (global can't be deleted) |
| GET, POST |
/Moonfin/Settings/detailsScreenBlur and /detailsScreenBlur/{profile}
|
Yes | Get or save the details-screen backdrop blur |
| GET, POST |
/Moonfin/Settings/detailsScreenOpacity and /detailsScreenOpacity/{profile}
|
Yes | Get or save the details-screen backdrop opacity |
See Settings Sync for the envelope shape and the full list of synced settings.
A user's sign-in PIN, stored on the server so it follows them to every device. A PIN is four digits. Only a salted PBKDF2-SHA256 hash is kept, and the PIN is never sent back.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Pin |
Yes | Whether the calling user has a PIN |
| PUT | /Moonfin/Pin |
Yes | Set the calling user's PIN. Body { "pin", "currentPin" }, where currentPin is required when a PIN already exists, and a wrong one is a 403 that counts as a guess |
| DELETE | /Moonfin/Pin |
Yes | Remove the calling user's PIN. Takes the same body, with currentPin
|
| POST | /Moonfin/Pin/Verify |
Yes | Check a PIN. Body { "pin" }. Answers 404 when the user has no PIN |
The first five wrong guesses are free. After that each one makes the user wait 30 seconds longer, up to 15 minutes, and while they wait every guess, even the right one, gets a 429 with Retry-After and retryAfterSeconds. The count survives a restart, and a correct PIN or an admin setting a new one clears it.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /Moonfin/Admin/ApplyDefaults |
Admin | Push admin defaults onto users' stored settings. Body { "overwrite", "userIds", "profiles", "keys" }. userIds null means everyone, profiles empty means all four, keys null means every set default, otherwise only those settings by JSON name. overwrite resets each user to the defaults alone and can't take keys. Returns usersAffected and orphansDeleted
|
| POST | /Moonfin/Admin/CopySettings |
Admin | Copy one user's saved profiles onto others. Body { "fromUserId", "toUserIds", "profiles", "keys", "replace" }. replace makes each profile an exact copy and can't take keys. API keys and hidden items are never copied. Answers 404 when the source has no settings |
| POST | /Moonfin/Admin/PushDefaults |
Admin | Older route. Applies every profile's defaults to all users (overwrite=true resets everyone, otherwise merges) |
| POST | /Moonfin/Admin/PushDefaults/{userId} |
Admin | Older route. Applies every profile's defaults to a single user |
| POST | /Moonfin/Broadcast |
Admin | Send an announcement to all users, over the SSE stream for connected clients and as a push to registered devices |
| GET | /Moonfin/Libraries/CheckWriteAccess |
Admin | Test whether the server can write metadata to each library, and report failing paths |
| GET | /Moonfin/Admin/Pins |
Admin | Every user with whether they have a PIN, administrators first, for the Accounts tab |
| PUT, DELETE | /Moonfin/Users/{userId}/Pin |
Admin | Set or remove one user's PIN. Setting a PIN replaces the old one without asking for it and clears the wrong-guess count, which is how a forgotten PIN is reset |
| GET | /Moonfin/Admin/ConfigBackup |
Admin | Jellyfin only. Whether the plugin settings look like they were reset while a backup with real settings survives: { "looksReset": bool, "backupPath": "..." }. The config page uses it to offer a restore |
| POST | /Moonfin/Admin/RestoreConfig |
Admin | Jellyfin only. Copy the backup over the live plugin settings. Returns 404 when there's no backup. Restart the server afterwards, since Jellyfin only reads the file at startup |
Admin messages are a stored, targeted successor to the one-shot broadcast: a message is saved on the server, filtered to the audience it was meant for, and delivered to connected clients over the SSE stream (as a messagesChanged event) and as a push to registered devices. Visibility is decided on the server, so a message meant for one user is never sent to another.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Messages |
Yes | The messages the calling user should see right now, already filtered to their audience and any start or end date. Returns 503 when settings sync is disabled |
| GET | /Moonfin/Admin/Messages |
Admin | Every stored message, including scheduled and expired ones, for the admin panel |
| POST | /Moonfin/Admin/Messages |
Admin | Create a message, or replace one in place when the ID already exists. Emits a messagesChanged event and, for a new interrupting message, a push |
| POST | /Moonfin/Admin/Messages/Order |
Admin | Reorder the stored messages to match the given list of IDs. The app shows them in this order, so this is what the up and down arrows drive |
| DELETE | /Moonfin/Admin/Messages/{messageId} |
Admin | Delete one message by ID |
A message carries a title, a Markdown body, a colour, a delivery mode (an unread badge on the menu button, or the window opening on its own), an audience (everyone, a set of users, or admins only), optional start and end dates, and an optional link button. Interrupting messages push to devices that don't have the app open, while inbox messages wait for the user to open it. The old /Moonfin/Broadcast still works for a quick one-off announcement that isn't stored.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/MediaBar |
Yes | The resolved media bar items for the current user (profile query, default global) |
| GET | /Moonfin/Genres |
Yes | All genre names and ids across the user's movie and series libraries |
| GET | /Moonfin/Themes |
Yes | List uploaded custom themes |
| GET | /Moonfin/Themes/{themeId} |
Yes | Get one custom theme by id |
| GET | /Moonfin/Admin/Themes |
Admin | Theme metadata index for the admin panel |
| POST | /Moonfin/Admin/Themes |
Admin | Upload or replace a theme payload |
| DELETE | /Moonfin/Admin/Themes/{themeId} |
Admin | Delete a theme |
See Themes for the editor and upload flow.
Jellyfin only.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Items/{id}/Similar |
Yes | Similar items for a movie or series, scored by Moonfin on the server. Optional limit (default 20, capped at 200), excludeItemIds, and userId (defaults to the caller). Results are filtered to the libraries the user can see and come back as { "Items": [...], "TotalRecordCount": n }, in the same card shape as the media bar with the user's UserData. Returns 404 for an unknown item, and an empty list when Use Moonfin Recommends for similar items is off |
This endpoint works on every supported Jellyfin version. On Jellyfin 12 Moonbase also plugs into Jellyfin's own similar items system, so the stock /Items/{id}/Similar returns Moonfin's scoring to every client, with Jellyfin's own providers only filling empty slots. Add bypass=moonfin (or engine=jellyfin) to that stock request to get Jellyfin's own results for one call.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Seasonal/Row |
Yes | The seasonal Home row for the calling user: holiday movies they own, plus Seerr suggestions. Optional country is the viewer's ISO alpha-2 code, ZZ for someone who picked Other, or empty to fall back to the server's. Answers { "holiday", "country", "items", "suggestions" }, with holiday null when no holiday window is open. items are the same cards the browse endpoints return, and suggestions use the custom row item shape with a rating attached. On a failure it answers an empty row rather than an error |
Filler, canon and recap markers come from the cache the Moonfin Anime Markers Sync task fills. Subbed and Dubbed are read from the audio tracks in the files.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/AnimeMarkers/Series |
Yes | Markers for every episode of one series (seriesId). Reads the cache only and never goes to the internet, so clients can call it on every episode list. Answers enabled: false when both marker features are off, and pending: true for a matched series that hasn't been fetched yet. Returns 400 for a missing or malformed id and 404 for an unknown series |
| GET | /Moonfin/AnimeMarkers/Items |
Yes | Subbed or Dubbed for up to 200 comma-separated item ids (ids). Series and folders are skipped, since their episodes and seasons come from the Series endpoint. Answers enabled: false when audio markers are off |
| GET | /Moonfin/AnimeMarkers/Diagnostics |
Admin | Match counts for the admin page: how many series matched a show, how many are waiting on a fetch, and which matched nothing |
| GET | /Moonfin/AnimeMarkers/Preview |
Admin | One series' episode list with its markers (seriesId), for the Preview a series tool |
| POST | /Moonfin/AnimeMarkers/Refresh |
Admin | Fetch one series right away instead of waiting for the nightly task (seriesId) |
| GET | /Moonfin/AnimeMarkers/Log |
Admin | The tail of the marker debug log (lines, default 200, up to 2000) |
| POST | /Moonfin/AnimeMarkers/ClearLog |
Admin | Empty the marker debug log |
| POST | /Moonfin/AnimeMarkers/ClearCache |
Admin | Drop every cached show so the next sync fetches from scratch |
A Series response looks like this:
{
"enabled": true,
"matched": true,
"slug": "naruto-shippuden",
"title": "Naruto Shippuden",
"pending": false,
"recapKnown": true,
"episodes": {
"<episodeId>": { "kind": "Filler", "recap": false, "audio": "Subbed" }
},
"seasons": {
"<seasonId>": { "audio": "Dubbed" }
},
"placement": "below"
}kind is Filler, Mixed, MangaCanon, AnimeCanon, or null when there's no marker or that pill is turned off. audio is Subbed, Dubbed, or SubbedAndDubbed when dual audio is shown separately. placement is the admin's pill placement (below, beside, or thumbnail). The Items endpoint answers { "enabled": true, "items": { "<itemId>": { "audio": "Subbed" } }, "placement": "below" }.
On Jellyfin the episode and season keys are item ids without hyphens. On Emby they're Emby's numeric item ids, the Items endpoint keys each answer by the id you sent, and fields with no value are left out instead of being sent as null.
Incomplete recording detection and re-recording. The settings are server-wide and set on the admin page's Live TV tab.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/LiveTv/Recordings/Incomplete |
Live TV access | The incomplete state of each recording listed in itemIds, or of every incomplete recording when none are listed. Recordings that aren't incomplete are left out |
| POST | /Moonfin/LiveTv/Recordings/{itemId}/Dismiss |
Live TV management | Keep as Complete. Clears the recording's incomplete state for everyone and removes its DVRIncompleteRecording tag |
| POST | /Moonfin/LiveTv/CompleteShowing |
Live TV management | Ask for a later showing of a program's episode or movie to be recorded. Repeating the call for the same one joins the same request, so it's safe to retry |
| GET | /Moonfin/LiveTv/CompleteShowing/Options |
Live TV management | For a program that's already airing (programId), whether a later showing can be searched for and the one found: name, description, start, channel and alreadyScheduled. Only channels the caller can see are searched |
| POST | /Moonfin/LiveTv/CompleteShowing/Suggestion |
Live TV management | Record the later showing that Options suggested. Answers 204, or 409 when that airing changed, was canceled or can't be seen |
| GET | /Moonfin/LiveTv/Settings/IncompleteRecordings |
Live TV access | The server-wide settings |
| POST | /Moonfin/LiveTv/Settings/IncompleteRecordings |
Admin | Change the server-wide settings |
These use the calling user's TMDB key, or the server-wide one, and answer 404 without either.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Tmdb/Thumb |
Yes | A 302 to the TMDB backdrop with the title on it for a title the server doesn't hold (type is movie or tv, plus tmdbId, or imdbId when there's no TMDB id). It prefers the backdrop in the server's metadata language, then TMDB's main one. scheme=http asks for a plain http image, for clients that can't load https. Paths are cached for 7 days |
| GET | /Moonfin/Tmdb/Details |
Yes | Overview, rating, genres, runTimeTicks, a textless backdrop, a logo and a YouTube trailer for a title the server doesn't hold (type, tmdbId or imdbId), in the server's metadata language. Shares Thumb's cache |
| GET | /Moonfin/Tmdb/PersonLinks |
Yes | A person's IMDb id, website, and Instagram, X, Facebook, TikTok and YouTube handles (tmdbId). Cached for 24 hours |
| GET | /Moonfin/Tmdb/Reviews |
Yes | TMDB user reviews for a title (tmdbId, type, language), up to 20, with the HTML turned into light Markdown. Asks for English when the requested language has none. Cached for 24 hours per title and language |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/MdbList/Ratings |
Yes | MDBList ratings for a title (type = movie or show, tmdbId), filtered to the user's chosen sources. An optional profile query (desktop, mobile, or tv) resolves the sources against that device profile, anything else falls back to global
|
| GET | /Moonfin/MdbList/KeyInfo |
Admin | Validate an MDBList API key and return the account's plan and remaining quota (backs the Test Key button, optional key query tests an unsaved key, otherwise the server-wide key is used) |
| POST | /Moonfin/MdbList/ClearCache |
Admin | Drop every cached MDBList rating so lookups refetch from the API |
| GET | /Moonfin/MdbList/Lists |
Yes | The cached catalog of MDBList official lists |
| GET | /Moonfin/MdbList/Lists/{slug}/Items |
Yes | Cached items for one official list (optional mediatype) |
| GET | /Moonfin/Tmdb/EpisodeRating |
Yes | TMDB rating for one episode (tmdbId, season, episode) |
| GET | /Moonfin/Tmdb/SeasonRatings |
Yes | TMDB ratings for every episode in a season (tmdbId, season) |
| GET | /Moonfin/Tmdb/NextEpisode |
Yes | The next episode to air for a series (tmdbId), so clients can show an air date without Sonarr. Answers { "success", "airDate", "seasonNumber", "episodeNumber", "name" }, or success: false with an error when there's no TMDB key or nothing is scheduled. Uses the user's TMDB key or the server-wide one, and caches each series for 6 hours for all users |
| GET | /Moonfin/Tmdb/ProductionCompanies |
Yes | TMDB studios for a title (tmdbId, type), each flagged for logo availability |
| GET | /Moonfin/Tmdb/StudioImage/{companyId} |
Yes | A cached studio logo PNG (re-downloaded from TMDB if evicted) |
| GET | /Moonfin/Assets/{fileName} |
No | Bundled rating provider icons |
| GET | /Moonfin/UserRatings/Mine |
Yes | Every personal rating the calling user has set, in one response, so a client can sort a library by My Rating and filter it by liked or disliked. Neither server has a user rating sort of its own |
| POST, DELETE | /Moonfin/UserRatings/{itemId} |
Yes | Emby only. Set the calling user's rating for an item (rating out of ten, or likes for a thumb) or clear it. Emby's own rating route answers 200 but stores nothing, so Moonfin writes through here |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/CustomRows/Items |
Yes | Resolve an external home row (source, type, params) into items, cached server-side for 24 hours. Items carry officialRating (the TMDB certification), overview, genres and runTimeTicks, and the response is filtered by the calling user's parental limit, where a title with no known rating is left out under a limit. A row fetched with the user's own TMDB or MDBList key is cached for that user only. An optional language (a BCP 47 tag like fr or pt-BR) fetches MDBList, TMDB and Letterboxd rows in that language and caches each language apart. IMDb rows stay in English. Items without an overview get the overview, genres and runtime from TMDB in the server's metadata language. On Jellyfin a resolve keeps running if the client disconnects, and a repeat request joins the one in progress |
| GET | /Moonfin/Collections/{collectionId}/Order |
Yes | The current user's saved item order for a collection |
| POST | /Moonfin/Collections/{collectionId}/Order |
Yes | Save the user's item order for a collection (empty array clears it) |
Jellyfin only.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Bookmarks |
Yes | Every bookmark the calling user has, across items |
| GET | /Moonfin/Bookmarks/{itemId} |
Yes | One item's bookmarks and notes for the calling user |
| POST | /Moonfin/Bookmarks/{itemId} |
Yes | Save the item's bookmarks for the calling user |
| POST | /Moonfin/Bookmarks/{itemId}/Notes |
Yes | Save the item's notes for the calling user |
Clients work from local storage first and reconcile with these, so nothing waits on the network to open a book.
All game endpoints require the game library feature to be enabled. See Retro Games for the full guide.
A library backed by RomM answers the same endpoints. Its game ids look like romm-12 and its BIOS ids like romm-fw-3, and the ROM and BIOS streams come from RomM through the server. For a user who linked their RomM account, those calls use that user's own RomM key, and the saves of RomM's games go to their RomM account. Save states are keyed ejs-<core>-romm-<id> or lr-<core>-romm-<id>, and battery saves (kind=sram) use the bare game id.
The EmulatorJS player page takes an optional sram URL next to save. It loads that battery save when the game starts and skips it when save is given, since a save state already holds it. window.moonfinGetSram() returns the battery save as base64 for the app to upload on exit.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Games/Libraries |
Yes | Libraries treated as game (ROM) libraries |
| GET | /Moonfin/Games/{libraryId}/Systems |
Yes | Top-level system folders in a game library |
| GET | /Moonfin/Games/{libraryId}/Games |
Yes | Games in a library, optionally filtered by system
|
| GET | /Moonfin/Games/{libraryId}/Games/{gameId} |
Yes | One game's full detail (ROM, core, BIOS) |
| GET | /Moonfin/Games/{libraryId}/Thumb/{gameId} |
Yes | Stream a game's box art or screenshot (type query), downloaded and cached on first request |
| GET, HEAD | /Moonfin/Games/{libraryId}/Rom/{token} |
Yes | Stream a ROM file, auto-extracting archives, with range support |
| GET, HEAD | /Moonfin/Games/{libraryId}/Rom/{token}/{fileName} |
Yes | Jellyfin only. The same stream with an explicit file name, which some cores need to identify the ROM |
| GET, HEAD | /Moonfin/Games/{libraryId}/Bios/{token} |
Yes | Stream a BIOS file a core needs |
| GET | /Moonfin/Games/Cores/Status |
Yes | Whether the self-hosted emulator cores are installed or downloading |
| POST | /Moonfin/Games/Cores/Install |
Admin | Download and install the cores bundle in the background |
| POST | /Moonfin/Games/Cores/Upload |
Admin | Install cores from an uploaded zip |
| GET | /Moonfin/Games/Saves/{gameId} |
Yes | Download a saved game blob for the current user (kind is state, sram or settings, default state) |
| PUT | /Moonfin/Games/Saves/{gameId} |
Yes | Upload or overwrite a saved game blob (max 32 MB) |
| GET | /Moonfin/Games/Romm/Account |
Yes | The current user's RomM link. While a link waits for approval, each call also checks with RomM. Returns {available, linked, username, pending, error}
|
| POST | /Moonfin/Games/Romm/Account |
Yes | Start linking the current user's RomM account. pending holds userCode, verificationUrl, verificationUrlComplete, expiresInSeconds and intervalSeconds
|
| DELETE | /Moonfin/Games/Romm/Account |
Yes | Unlink the current user's RomM account |
| GET | /Moonfin/EmulatorJS/player.html |
No | The in-browser player shell |
| GET | /Moonfin/EmulatorJS/data/{**path} |
No | Self-hosted EmulatorJS runtime files, with a CDN fallback when not installed |
| GET | /Moonfin/Games/Debug |
Admin | Diagnostics for game library detection |
| POST | /Moonfin/Games/Romm/Test |
Admin | Check a RomM address and token from the admin page before saving them. Body {"url", "token"}
|
| PUT | /Moonfin/Games/{libraryId}/Games/{gameId}/Core |
Yes | Jellyfin only. Pin one game to a specific core |
| PUT | /Moonfin/Games/{libraryId}/Games/{gameId}/Backend |
Yes | Jellyfin only. Pin one game to the native or EmulatorJS backend |
Jellyfin only.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Games/ArtworkCapabilities |
Yes | Advertises the manifest-driven artwork protocol, so older clients keep the old path |
| GET | /Moonfin/Games/{libraryId}/ArtworkManifest |
Yes | The cataloged artwork state for one system, without scheduling any provider work. Returns 304 when nothing changed |
| POST | /Moonfin/Games/{libraryId}/ArtworkPriority |
Yes | Promotes already cataloged artwork into the order the client actually needs it |
| GET | /Moonfin/Games/{libraryId}/Artwork/{gameId}/{role}/{revision} |
Yes | One versioned artwork file, served locally |
| POST | /Moonfin/Games/{libraryId}/Artwork/{gameId}/Refresh |
Admin | Repair path that reopens and reschedules one artifact |
| POST | /Moonfin/Games/{libraryId}/Artwork/Refresh |
Admin | Library-wide repair, optionally for one system. Checks each system's game database for updates, then reopens artwork that never found an original. Answers 202 and runs in the background, or 409 when a refresh is already running |
Manifest entries carry each image's width and height, and ArtworkCapabilities answers dimensions: true, so a client can shape a system's grid around its box art.
Jellyfin only.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Games/ArcadeCompatibility/Status |
Admin | Whether the FBNeo and MAME data files are installed, and what they cover |
| PUT | /Moonfin/Games/ArcadeCompatibility/{core}/Dat |
Admin | Replace one core's data file with an uploaded XML, up to 512 MB |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Transcodes/Active |
Admin | Active transcode and download jobs with progress and session info (includePlayback adds HLS playback jobs) |
| DELETE | /Moonfin/Transcodes/Active/{jobId} |
Admin | Cancel an active job |
| GET | /Moonfin/Transcodes/Mine |
Yes | Jellyfin only. The caller's own transcode jobs, scoped by the device id on its token, so a client can show progress and an ETA for a download it started |
Emby only. Jellyfin has POST /ClientLog/Document of its own and Moonfin uses that there. Emby has no equivalent anywhere in its API, so the plugin provides one, which is what makes the app's Send report to server button work on Emby.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /Moonfin/ClientLog/Document |
Yes | Upload a diagnostic or crash report as text/plain. The report is written into the server's log folder as upload_<client>_<version>_<utc>.txt, matching the .txt Emby writes its own logs as, so it appears under Logs beside them. The response names the file: { "FileName": "..." }
|
Not admin-only on purpose: crash reports come from whichever user hit the bug. The guards are elsewhere. The body is capped at 1 MB (413 past it), each user gets 10 uploads an hour (429 past that), the file name is built entirely on the server from the authenticated session rather than anything the client sends, and the whole endpoint returns 503 when Enable client log upload is off in the plugin settings. Clients redact server addresses, IP addresses and access tokens before sending.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Seerr/Config |
Yes | Seerr config for the client (see the response shape below) |
| POST | /Moonfin/Seerr/Login |
Yes | Sign in to Seerr with Jellyfin/Emby or local credentials and store the session |
| GET | /Moonfin/Seerr/Status |
Yes | Whether Seerr is enabled and the current user's session status |
| GET | /Moonfin/Seerr/Validate |
Yes | Confirm the stored session is still valid |
| DELETE | /Moonfin/Seerr/Logout |
Yes | Log out and clear the stored session |
| GET | /Moonfin/Seerr/Radarr/Calendar |
Yes | The upcoming Radarr calendar (optional start and end). The server reads the Radarr connection from Seerr with a stored Seerr admin session and calls Radarr itself, so the API key stays on the server and remote clients still see it. Returns 503 when Seerr is off or no Seerr admin has signed in through Moonfin, and 404 when Seerr has no Radarr server. It uses Seerr's regular (non-4K) default Radarr, and when Seerr's internal address for it can't be reached it tries the External URL set in Seerr, but only over https or when that address is on the local network |
| GET | /Moonfin/Seerr/Sonarr/Calendar |
Yes | The same for Sonarr. Clients try it first for a series' next air date and fall back to TMDB |
| GET, POST, PUT, DELETE | /Moonfin/Seerr/Api/{**path} |
Session | Authenticated proxy to the Seerr API using the stored session. For a user with a parental limit, titles above it and unrated ones are left out of discover, search, recommendations, credits and collection results, and opening, requesting or watchlisting one answers 403. The rating comes from TMDB, so without a TMDB key such a user gets nothing |
See Reverse Proxy and Seerr for proxy and single sign-on notes.
{
"enabled": true,
"url": "https://seerr.example.com",
"displayName": "Seerr",
"variant": "seerr",
"userEnabled": true
}| Field | Type | Description |
|---|---|---|
enabled |
bool | Whether Seerr is enabled by the admin |
url |
string | The Seerr server URL used for proxying |
displayName |
string | The name shown in the client (admin override, defaults to Seerr) |
variant |
string | Always seerr on current versions |
userEnabled |
bool | Whether the user has Seerr enabled in their own settings |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET, POST | /Moonfin/Notifications/Prefs |
Yes | Get or save the caller's notification preferences, including the new media opt-in (notifyOnNewMedia) |
| POST, DELETE | /Moonfin/Notifications/Register |
Yes | Register or remove a push token for the caller's device |
| GET | /Moonfin/Notifications/WebhookInfo |
Admin | The Seerr webhook URL, secret, supported types, and provisioning status |
| POST | /Moonfin/Notifications/Reprovision |
Admin | Re-register Moonfin's webhook in Seerr immediately |
| POST | /Moonfin/Seerr/Webhook |
No (shared secret) | Inbound Seerr webhook, authenticated by the secret query or X-Moonfin-Webhook-Secret header |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /Moonfin/Web/{**path} |
No | Serve the Moonfin web app static files with SPA fallback |
| GET | /Moonfin/Web/config.json |
No | Runtime config for web plugin mode |
| GET | /Moonfin/Web/loader.js |
No | The loader bridge script for the stock Jellyfin header button |
| GET |
/Moonfin/Discovery and /Moonfin/Discovery/discover
|
No | Same-origin server metadata for web discovery |