Skip to content
PlinthioRelease 1.4.2

API ​

The web app is built entirely on Plinthio's own REST API, so anything it does, a script can do. Everything is JSON under /api.

Authentication ​

MethodHowUse it for
API keyX-API-Key: plinthio_…Scripts, dashboards, home automation
API key over HTTP BasicAuthorization: Basic base64(username:key)Apps that only do username and password: OPDS readers, Mihon
Session tokenPOST /api/auth/login, then Authorization: Bearer <token>The web app. Lasts 7 days, renewed by POST /api/auth/refresh
Media tokenPOST /api/auth/media-token, then ?token=<mediaToken>Links that can't carry headers (images, audio, video). Only accepted on /api/media/*, valid 24 hours
Komga session cookieSet by /api/v1 and /api/v2 after a key sign-inMihon's tracker. Only honoured on those paths
kosync headersx-auth-user: <username>, x-auth-key: md5(key)KOReader. Only on /api/kosync

Make API keys in Settings → Apps & API keys. A key acts as its owner, with their role, content limit and Kids Mode. A session token in a URL is refused, as is a media token in a header (P102).

With two-factor on, POST /api/auth/login returns { twoFactorRequired, challenge } instead of a token. Finish with POST /api/auth/login/2fa and { challenge, code } or { challenge, recoveryCode }.

bash
KEY=plinthio_...
curl -H "X-API-Key: $KEY" "http://plinthio:8088/api/items?mediaType=manga&progress=in_progress"

Errors ​

Every error is JSON with a code:

json
{ "error": "The media file is missing from disk", "code": "P301" }

Admins also get a detail field with the underlying cause. GET /api/errors returns the whole list of codes, with no sign-in needed.

Rate Limits ​

ScopeLimit
/api/auth/login, /api/auth/login/2fa10 failed attempts per 15 minutes per address
The rest of /api/auth60 per 15 minutes
General API600 per minute
/api/media, /api/opds, /api/v1, /api/v2, /api/kosync1200 per minute
Making, downloading and copying backups12 per 15 minutes

A limited request gets HTTP 429 with P005 (or P108 for sign-in). Behind a reverse proxy, set TRUST_PROXY so limits apply per client rather than to everyone at once.

Routes ​

Paths below are relative to /api. V means any signed-in user, E editor or admin, A admin. Responses respect hidden titles, missing files, content limits and Kids Mode for the caller.

Sign-In and Account ​

RouteWhoWhat it does
GET /auth/setup-status, POST /auth/setuppublicThe first-run wizard. Only while no users exist, and only from the home network
POST /auth/login, GET /auth/me, POST /auth/refreshpublic / VSign in, who am I, renew
POST /auth/login/2fapublicSecond step of a two-factor sign-in. Five tries per challenge
POST /auth/media-tokenVMedia token for links
POST /auth/sign-out-everywhereVRevoke every token for your account
GET /auth/accesspublicWhether this device is home, Tailscale or outside, and whether it may sign in from there
GET /auth/2fa, POST /auth/2fa/setup, /2fa/enable, /2fa/disable, /2fa/recovery-codesV (session only, not API keys)Two-factor for your own account
PATCH /users/preferences, PATCH /users/passwordVYour preferences (merged, not replaced) and password
POST /users/avatar, DELETE /users/avatar, GET /users/:id/avatarVProfile picture
GET /keys, POST /keys, DELETE /keys/:idVYour API keys. A new key is returned once

Library and Titles ​

RouteWhoWhat it does
GET /librariesVLibraries with visible item counts
POST /libraries, DELETE /libraries/:id, POST /libraries/:id/scan, GET /libraries/browseAManage libraries and scans
PATCH /libraries/:id with { kidsAllowed }EKids Mode for a whole library
GET /itemsVTitles. Filters: libraryId, mediaType, author, series, search, progress (unread, in_progress, finished, skipped), genre, addedWithinDays, sort, limit, offset
GET /items/:id, /items/:id/extras, /credits, /collection, /chaptersVOne title, its extras, TMDB credits and facts, its collection, chapters
GET /items/series, /items/series/:name?library=&type=VSeries list and one series
POST /items/series/:name/mark-read, /mark-unreadVA whole series
GET /items/genres, /items/authors, /items/foldersVFilter data and disk folders
POST /items/:id/hide, /unhideV / AHide for yourself, or for everyone with { "global": true } (admins)
GET /items/hiddenVWhat you've hidden
GET /series/:libraryId/:name/settings, PUTV / ESeries name, reading direction, age rating
GET /kids, GET /kids/status, POST /kids/titles, DELETE /kids/titles/:idEKids Mode series and titles

Progress, Bookmarks and Ratings ​

RouteWhoWhat it does
GET /progress/continueVThe Continue row
GET /progress/:itemId, POST /progress/:itemIdVRead or save a position (currentTime/duration, currentPage/totalPages, isFinished, cfi for EPUB, playbackRate for audio)
POST /progress/finish with { itemIds, finished }VMark several finished or not started
POST /progress/skip with { itemIds, skipped }VSkip or unskip volumes
GET /bookmarks/:itemId, POST /bookmarks, PATCH and DELETE /bookmarks/:idVBookmarks and notes
GET /highlights/:itemId, POST /highlights, PATCH and DELETE /highlights/:idVEPUB highlights: cfiRange, text, color (yellow, green, blue, pink, orange), optional note
GET /ratings/:itemId, PUT with { rating }, DELETEVYour stars, the community average and TMDB's score (as enabled)
POST /activity/start, /end, GET /activity/me, GET /activity/adminV / AReading and watching sessions, sign-in history
GET /stats/me, GET /stats/adminV / AStatistics

Media ​

These accept a media token as ?token=.

RouteWhat it does
GET /media/cover/:id?w=, /media/still/:idCover thumbnails (WebP) or the original (raw=true), and episode stills
GET /media/stream/:idAudio, with byte ranges
GET /media/manga/:id/pages, /media/manga/:id/page/:indexPage list and page images (0-based) for comics, manga and PDFs
GET /media/book/:id/fileThe EPUB or PDF file
GET /media/video/:id/playback-info?clientHevc=Playback mode, tracks and qualities
GET /media/video/:id/streamDirect play, with byte ranges
GET /media/video/:id/hls/master.m3u8?audio=, POST …/hls/stopHLS streaming
GET /media/video/:id/subtitles/:track.vttSubtitles as WebVTT
GET /media/video/:id/trickplay/index.json, sheet_N.jpgScrub previews
GET /media/video/:id/markers, PUT (E)Intro and credits ranges

Lists, Requests and Parties ​

RouteWhoWhat it does
/collections…VCustom folders and lists: create, add library or outside titles, reorder, remove
GET /requests, POST /requests, DELETE /requests/:idVYour requests
GET /requests/pending-count, PATCH /requests/:idEThe review queue
POST /party, GET /party/:code, GET /party/:code/events, POST /party/:code/{action,buffering,item,settings,chat}, DELETE /party/:codeVWatch parties (when turned on). Events are server-sent events

Metadata ​

RouteWhoWhat it does
GET /metadata/search?mediaType=&query=&year=VSearch providers
POST /metadata/apply/:itemId, /metadata/cover/:itemId, /metadata/series-coverEApply a match, upload covers
GET /metadata/admin/items, POST /metadata/admin/match-single/:itemId, /batch-match, /batch-clean-titlesEBulk tools

Server ​

RouteWhoWhat it does
GET /customization, PATCHpublic / ABranding, theme, layout, ratings, collections, parties, pause screen, opening sequence
POST /customization/intro, DELETEAUpload (multipart field intro) or remove the opening sequence clip
GET /media/introVThe opening sequence clip
GET /settings/filters, PATCHV / AWhich shelf views are offered
/settings/transcoding, /transcoding/test, /metadata-providers, /metadata-providers/tmdb-key, /auto-scan, /backup/*AServer settings and backups
GET /admin/health, POST /admin/health/remove-missingALibrary Health, and removing missing titles
POST /admin/health/offload, /unoffloadAKeep titles as history ({ itemIds }), or undo it
GET /admin/logs, DELETEAServer log
GET /users, POST /users, PATCH /users/:id, /:id/role, /:id/password, /:id/extend, DELETE /users/:idAAccounts
POST /users/:id/two-factor/resetATurn off someone's two-factor and sign them out
GET /admin/network, PATCHAAway-from-home settings and status
GET /system/updateAUpdate check status
GET /health, GET /errorspublicHealth check (with version) and the error code list

Reading Apps ​

PrefixWhat it is
/api/opdsOPDS 1.2 catalog with page streaming (HTTP Basic, key as password)
/api/v1, /api/v2The Komga-compatible subset Mihon uses
/api/kosyncKOReader progress sync

Examples ​

Intro and Credits Markers ​

There's no screen for setting intro and credits ranges yet. Editors and admins set them per episode through the API. The request replaces all of that episode's markers. Types are intro and credits.

bash
curl -X PUT -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"markers":[{"type":"intro","startSeconds":62,"endSeconds":152},{"type":"credits","startSeconds":2580,"endSeconds":2640}]}' \
  http://plinthio:8088/api/media/video/<itemId>/markers

Hiding a Title From Everyone ​

Admins can hide a title for every account, and undo it:

bash
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"global": true}' http://plinthio:8088/api/items/<id>/hide

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"global": true}' http://plinthio:8088/api/items/<id>/unhide

Health Check ​

bash
curl http://<server>:8088/api/health

Returns {"status":"healthy","version":"…","app":"Plinthio"}.

Odd Omens is a one-person studio building privacy-first software.