Skip to content

API Reference

Version: 0.1.0

Interactive docs

With the server running, the API is self-documented via OpenAPI:

URLDescription
http://localhost:9481/api/docsSwagger UI — interactive, try-it-out docs
http://localhost:9481/api/redocReDoc — clean, readable reference
http://localhost:9481/api/openapi.jsonRaw OpenAPI schema

Authentication

All endpoints except /api/auth/status, /api/auth/setup, /api/auth/login, and /api/auth/config require a JWT.

Header (preferred):

Authorization: Bearer <token>

Query parameter (required for browser-embedded images and file downloads):

?token=<token>

Tokens are returned by /api/auth/login and expire after 30 days.

Roles

RolePermissions
adminFull access including user management and app settings
gmRead + edit metadata, rescan library, manage campaigns
playerRead-only access

Auth

EndpointMethodAuthDescription
/api/auth/statusGETReturns {"initialized": bool}
/api/auth/configGETPublic auth config for the login screen
/api/auth/setupPOSTFirst-run admin account creation. Body: {username, password}
/api/auth/loginPOSTAuthenticate. Body: {username, password}. Returns {token, user}
/api/auth/meGETanyCurrent user details
/api/auth/openid/loginGETStart OIDC login, redirects to IdP
/api/auth/openid/callbackGETOIDC callback
/api/auth/openid/discoverPOSTadminServer-side discovery fetch. Body: {issuer_url}

Users

EndpointMethodAuthDescription
/api/usersGETadminList all users
/api/usersPOSTadminCreate a user. Body: {username, password, role?, email?}
/api/users/:idPATCHadminUpdate role, password, allow_explicit, or email
/api/users/:idDELETEadminDelete a user
/api/users/me/preferencesPATCHanyUpdate own display_name, allow_explicit, or email
/api/users/me/passwordPATCHanyChange own password. Body: {current_password, new_password}
/api/users/meDELETEanyDelete own account

Library

EndpointMethodAuthDescription
/api/statsGETJWT or X-API-KeyCounts, page totals, library size, version
/api/scan-statusGETadminCurrent scan state
/api/rescanPOSTadminTrigger a background rescan and reindex
/api/cancel-scanPOSTadminGracefully stop the running scan

Stats response:

json
{
  "game_systems": 12,
  "books": 340,
  "maps": 1500,
  "tokens": 800,
  "indexed_books": 320,
  "total_pages": 45000,
  "total_size_mb": 18240.5,
  "version": "1.0.0"
}

Game Systems

EndpointMethodAuthDescription
/api/systemsGETanyList all systems with book counts
/api/systems/:idGETanySystem detail + full book list
/api/systems/:idPATCHgm/adminUpdate metadata

PATCH fields: name, slug, description, publishers, character_builder_url, cover_image, cover_book_id, tags, genre, is_explicit


Books

EndpointMethodAuthDescription
/api/booksGETanyPaginated book list. Query: system_id, category, limit (max 500), offset
/api/books/:idGETanyBook detail
/api/books/:idPATCHgm/adminUpdate book metadata
/api/books/:id/fileGETanyDownload/stream the file
/api/books/:id/thumbnailGETanyWebP cover thumbnail
/api/books/:id/tocGETanyPDF table of contents
/api/books/:id/page/:numGETanyRender PDF page as WebP. Query: width (default 1200, max 3000)
/api/books/:id/page/:num/textGETanyPlain text of a page
/api/books/:id/page/:num/wordsGETanyWord bounding boxes for text overlay

Maps

EndpointMethodAuthDescription
/api/mapsGETanyPaginated map list. Query: limit, offset, tag
/api/maps/:idGETanyMap detail
/api/maps/:idPATCHgm/adminUpdate description, tags, map_type, grid_size
/api/maps/:id/fileGETanyDownload/stream the map image
/api/maps/:id/thumbnailGETanyWebP thumbnail
/api/map-foldersGETanyList folder tag assignments
/api/map-foldersPATCHgm/adminSet tags on a folder. Body: {path, tags}

Tokens

EndpointMethodAuthDescription
/api/tokensGETanyPaginated token list. Query: limit, offset, tag
/api/tokens/:idGETanyToken detail
/api/tokens/:idPATCHgm/adminUpdate description, tags, is_explicit
/api/tokens/:id/fileGETanyDownload the token image
/api/tokens/:id/thumbnailGETanyWebP thumbnail
/api/token-foldersGETanyList folder tag assignments
/api/token-foldersPATCHgm/adminSet tags on a folder. Body: {path, tags}

EndpointMethodAuthDescription
/api/search?q=GETanyFTS5 full-text search. Min 2 chars. Optional: book_id, system_id, limit

Response:

json
{
  "query": "fireball",
  "total": 42,
  "results": [{"id": "uuid", "title": "...", "game_system": "...", "page_number": 42, "snippet": "..."}],
  "maps":    [{"id": "uuid", "filename": "...", "relative_path": "...", "tags": []}],
  "tokens":  [{"id": "uuid", "filename": "...", "relative_path": "...", "tags": []}]
}

maps and tokens are empty when book_id or system_id is scoped.


Favorites

EndpointMethodAuthDescription
/api/favoritesGETanyList current user's favorites
/api/favoritesPOSTanyAdd a favorite (idempotent). Body: {item_type, item_id}
/api/favorites/:type/:idDELETEanyRemove a favorite

Item types: book, map, token, system


Bookmarks

EndpointMethodAuthDescription
/api/bookmarks?book_id=GETanyList user's bookmarks for a book
/api/bookmarksPOSTanyCreate a bookmark. Body: {book_id, page_number, label?, notes?, selected_text?}
/api/bookmarks/:idPATCHanyUpdate label or notes
/api/bookmarks/:idDELETEanyDelete a bookmark

Campaigns

Campaign CRUD

EndpointMethodAuthDescription
/api/campaignsGETanyList own + invited campaigns
/api/campaignsPOSTanyCreate campaign
/api/campaigns/:idGETowner or memberCampaign detail
/api/campaigns/:idPATCHowner or adminUpdate campaign
/api/campaigns/:idDELETEowner or adminDelete campaign

Members

EndpointMethodAuthDescription
/api/campaigns/:id/invitePOSTowner or adminInvite a user. Body: {user_id}
/api/campaigns/:id/members/:user_idPATCHmember or ownerAccept/decline or set character name
/api/campaigns/:id/members/:user_idDELETEowner, admin, or selfRemove member

Sessions

EndpointMethodAuthDescription
/api/campaigns/:id/sessionsGETmember or ownerList sessions
/api/campaigns/:id/sessionsPOSTmember or ownerCreate session. Body: {session_date, title?}
/api/campaigns/:id/sessions/:sidPATCHowner or adminUpdate title
/api/campaigns/:id/sessions/:sidDELETEowner or adminDelete session
/api/campaigns/:id/sessions/:sid/notes/playerPUTmember or ownerSave player note. Body: {content}
/api/campaigns/:id/sessions/:sid/notes/gmPUTowner or adminSave GM notes. Body: {internal_content?, external_content?}

Schedule

EndpointMethodAuthDescription
/api/campaigns/:id/scheduleGETmember or ownerSchedule + next 10 dates
/api/campaigns/:id/schedulePUTowner or adminCreate or update schedule
/api/campaigns/:id/scheduleDELETEowner or adminRemove schedule

Schedule body:

json
{
  "frequency": "weekly",
  "days": [5],
  "time_utc": "18:00",
  "biweekly_reference": "2026-01-03",
  "monthly_week": null,
  "custom_dates": null
}

frequency values: weekly, biweekly, monthly, custom. Days are 0 (Monday) – 6 (Sunday).

Availability

EndpointMethodAuthDescription
/api/campaigns/:id/availabilityGETmember or ownerAvailability for next 10 scheduled sessions
/api/campaigns/:id/availability/:datePUTmember or ownerSet own availability. Body: {status}
/api/campaigns/:id/availability/:date/cancelPUTowner or adminToggle session cancellation

Statuses: available, tentative, unavailable


Settings (admin only)

EndpointMethodDescription
/api/settingsGETGet all application settings
/api/settingsPATCHUpdate application settings
/api/settings/uiGETUI visibility flags (any authenticated user)
/api/settings/api-key/generatePOSTGenerate a stats API key
/api/settings/api-keyDELETERevoke the stats API key

Maintenance (admin only)

EndpointMethodDescription
/api/maintenance/cleanup-missingPOSTRemove DB records for files no longer present on disk

Logs (admin only)

EndpointMethodDescription
/api/logsGETRetrieve recent log entries from the in-memory ring buffer

Query parameters: level (default info), limit (default 200, max 20000), offset, after_seq (cursor for live polling).


Error responses

json
{"detail": "Human-readable error message"}
StatusMeaning
400Bad request / business rule violated
401Not authenticated
403Forbidden — insufficient role
404Not found
409Conflict — duplicate resource
422Request body failed schema validation

Released under the GNU GPL v3.0 License.