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/statusGETNoneReturns {"initialized": bool}
/api/auth/configGETNonePublic auth config for the login screen
/api/auth/setupPOSTNoneFirst-run admin account creation. Body: {username, password}
/api/auth/loginPOSTNoneAuthenticate. Body: {username, password}. Returns {token, user}
/api/auth/meGETanyCurrent user details
/api/auth/openid/loginGETNoneStart OIDC login, redirects to IdP
/api/auth/openid/callbackGETNoneOIDC 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,
  "audio": 250,
  "indexed_books": 320,
  "total_pages": 45000,
  "total_size_mb": 18240.5
}

/api/stats is the only endpoint that accepts the X-API-Key header, so it's the safe way to surface library counts on an external dashboard. Generate a key as an admin under Settings → App Settings → Stats API Key (regenerate or revoke it there at any time). See the Homepage Widget guide for a full walkthrough.

Homepage Custom API widget: add this to your Homepage services.yaml (Custom API widget docs):

yaml
- Grimoire:
    href: https://grimoire.example.com
    icon: grimoire.png
    widget:
      type: customapi
      url: https://grimoire.example.com/api/stats
      refreshInterval: 60000
      headers:
        X-API-Key: your-key-here
      mappings:
        - field: books
          label: Books
          format: number
        - field: maps
          label: Maps
          format: number
        - field: tokens
          label: Tokens
          format: number
        - field: total_size_mb
          label: Size
          format: float
          scale: 0.001
          suffix: " GB"

Homepage shows up to four fields per row; pick the counts you care about from the fields below. Use a refreshInterval of 60s or higher, /api/stats is rate limited.

FieldMeaningSuggested format
game_systemsNumber of game systems (top-level library folders)number
booksTotal books (PDFs)number
mapsTotal mapsnumber
tokensTotal tokensnumber
audioTotal audio tracksnumber
indexed_booksBooks with a searchable full-text indexnumber
total_pagesSum of all book page countsnumber
total_size_mbTotal library size in MBfloat, add scale: 0.001 + suffix: " GB" to show GB

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/reindexPOSTgm/adminRe-run OCR on a scanned book. Optional query ocr_dpi (72–600) re-reads it at a higher resolution than the global OCR_DPI. Clears the search index and re-queues the book (OCR runs in the background). 400 for books with an embedded text layer.
/api/books/:id/rescanPOSTgm/adminRe-read a single book from disk and rebuild its search index, for a file edited externally. Works for any PDF: a text-layer book is re-extracted; an image-only book is re-queued for OCR. Refreshes page count and thumbnail. Runs in the background; no-ops if a library scan is already running. 400 for non-PDFs.
/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.