Skip to content

API Reference

Interactive API documentation generated from the OpenAPI spec.

API Version: 0.1.0

Initial setup

POST
/api/auth/setup

Create the first API key. Only works when no keys exist yet.

Request Body

application/json
JSON
{
  
"label": "string"
}

Responses

API key created - returns the raw key (shown only once)

application/json
JSON
{
  
"id": "string",
  
"label": "string",
  
"createdAt": "string",
  
"key": "string"
}

Samples


List API keys

GET
/api/auth/keys

List all API keys (hashes are never exposed)

Responses

Array of API key metadata

application/json
JSON
{
  
"keys": [
  
  
{
  
  
  
"id": "string",
  
  
  
"label": "string",
  
  
  
"isAdmin": true,
  
  
  
"createdAt": "string",
  
  
  
"lastUsedAt": "string"
  
  
}
  
]
}

Samples


Create API key

POST
/api/auth/keys

Generate a new API key with the given label

Request Body

application/json
JSON
{
  
"label": "string"
}

Responses

API key created - returns the raw key (shown only once)

application/json
JSON
{
  
"id": "string",
  
"label": "string",
  
"createdAt": "string",
  
"key": "string"
}

Samples


Delete API key

DELETE
/api/auth/keys/{id}

Revoke an API key. Cannot delete the last key or the key used for this request.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Key deleted

application/json
JSON
{
  
"deleted": true,
  
"id": "string"
}

Samples


Login with API key

POST
/api/auth/login

Validates the API key and sets an httpOnly session cookie. Used by the SPA frontend.

Request Body

application/json
JSON
{
  
"apiKey": "string"
}

Responses

Login successful

application/json
JSON
{
  
"authenticated": true
}

Samples


Logout

POST
/api/auth/logout

Clears the session cookie.

Responses

Logged out

application/json
JSON
{
  
"authenticated": true
}

Samples


Check session

GET
/api/auth/session

Returns whether the current session cookie is valid, with user info if authenticated.

Responses

Session status

application/json
JSON
{
  
"authenticated": true,
  
"isAdmin": true,
  
"label": "string",
  
"apiKeyId": "string"
}

Samples


health


Health check

GET
/api/health

Returns minimal status for unauthenticated requests. Provide a valid API key for detailed check info.

Responses

All systems healthy

application/json
JSON
{
  
"status": "string",
  
"service": "string",
  
"checks": {
  
  
"database": {
  
  
  
"status": "string",
  
  
  
"latencyMs": 0,
  
  
  
"error": "string"
  
  
},
  
  
"redis": {
  
  
  
"status": "string",
  
  
  
"latencyMs": 0,
  
  
  
"error": "string"
  
  
},
  
  
"eventBus": {
  
  
  
"status": "string",
  
  
  
"latencyMs": 0,
  
  
  
"error": "string"
  
  
}
  
}
}

Samples


Get full settings page status

GET
/api/settings/status

Aggregate endpoint that returns health checks, job queue status, failed jobs, app settings, and all credential statuses in a single request. Non-admin users receive only their credential connection status; admin users receive the full diagnostics payload.

Responses

Aggregated settings status

application/json
JSON
{
  
"health": {
  
  
"status": "string",
  
  
"checks": {
  
  
  
"database": {
  
  
  
  
"status": "string",
  
  
  
  
"latencyMs": 0,
  
  
  
  
"error": "string"
  
  
  
},
  
  
  
"redis": {
  
  
  
  
"status": "string",
  
  
  
  
"latencyMs": 0,
  
  
  
  
"error": "string"
  
  
  
},
  
  
  
"eventBus": {
  
  
  
  
"status": "string",
  
  
  
  
"latencyMs": 0,
  
  
  
  
"error": "string"
  
  
  
}
  
  
}
  
},
  
"queues": {
  
  
"additionalProperties": {
  
  
  
"waiting": 0,
  
  
  
"active": 0,
  
  
  
"completed": 0,
  
  
  
"failed": 0,
  
  
  
"delayed": 0,
  
  
  
"paused": 0
  
  
}
  
},
  
"failedJobs": {
  
  
"jobs": [
  
  
  
{
  
  
  
  
"id": "string",
  
  
  
  
"queueName": "string",
  
  
  
  
"name": "string",
  
  
  
  
"data": {
  
  
  
  
  
"additionalProperties": "string"
  
  
  
  
},
  
  
  
  
"error": "string",
  
  
  
  
"failedAt": 0,
  
  
  
  
"attemptsMade": 0,
  
  
  
  
"maxAttempts": 0
  
  
  
}
  
  
],
  
  
"total": 0
  
},
  
"settings": {
  
  
"libraryPath": "string",
  
  
"inboxPath": "string",
  
  
"kosyncConfigured": true,
  
  
"hardcoverMetadataEnabled": true,
  
  
"hardcoverSyncEnabled": true
  
},
  
"credentials": {
  
  
"opds": {
  
  
  
"configured": true,
  
  
  
"service": "string",
  
  
  
"username": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
},
  
  
"kosync": {
  
  
  
"configured": true,
  
  
  
"service": "string",
  
  
  
"username": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
},
  
  
"hardcover": {
  
  
  
"configured": true,
  
  
  
"service": "string",
  
  
  
"username": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string"
  
  
}
  
}
}

Samples


Get settings

GET
/api/settings

Return current library and inbox path settings

Responses

Current settings

application/json
JSON
{
  
"libraryPath": "string",
  
"inboxPath": "string",
  
"kosyncConfigured": true,
  
"hardcoverMetadataEnabled": true,
  
"hardcoverSyncEnabled": true
}

Samples


Update settings

PATCH
/api/settings

Update persistent application settings (Hardcover integration toggles). Library and inbox paths are configured via the LIBRIS_LIBRARY_PATH and LIBRIS_INBOX_PATH environment variables and cannot be changed at runtime.

Request Body

application/json
JSON
{
  
"hardcoverMetadataEnabled": true,
  
"hardcoverSyncEnabled": true
}

Responses

Settings updated

application/json
JSON
{
  
"updated": [
  
  
"string"
  
]
}

Samples


List library books

GET
/api/library

Paginated list of organized books with optional search and filtering

Parameters

Query Parameters

page

Page number

Type
integer
Minimum
1
Default
1
limit

Items per page

Type
integer
Minimum
1
Maximum
100
Default
20
author

Filter by author (partial match)

Type
string
Max Length
500
Default
""
genre

Filter by genre (exact, case-insensitive)

Type
string
Max Length
500
Default
""
language

Filter by language code (exact, case-insensitive)

Type
string
Max Length
500
Default
""
series

Filter by series name (exact match)

Type
string
Max Length
500
Default
""
uploaderId

Filter by uploader API key ID (exact match)

Type
string
Default
""
q

Full-text search across title, author, and description with typo tolerance

Type
string
Max Length
500
Default
""
sort

Sort order for results

Type
string
Default
"title_asc"

Responses

Paginated list of books with files

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"status": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"isbn10": "string",
  
  
  
"isbn13": "string",
  
  
  
"publisher": "string",
  
  
  
"publishedYear": 0,
  
  
  
"language": "string",
  
  
  
"description": "string",
  
  
  
"coverUrl": "string",
  
  
  
"coverPath": "string",
  
  
  
"pageCount": 0,
  
  
  
"series": "string",
  
  
  
"seriesIndex": 0,
  
  
  
"genres": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"tags": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"hardcoverBookId": 0,
  
  
  
"hardcoverEditionId": 0,
  
  
  
"createdBy": "string",
  
  
  
"possibleDuplicateOf": "string",
  
  
  
"approvedAt": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string",
  
  
  
"files": [
  
  
  
  
{
  
  
  
  
  
"id": "string",
  
  
  
  
  
"format": "string",
  
  
  
  
  
"originalName": "string",
  
  
  
  
  
"fileSize": "string"
  
  
  
  
}
  
  
  
],
  
  
  
"uploader": {
  
  
  
  
"id": "string",
  
  
  
  
"label": "string"
  
  
  
}
  
  
}
  
],
  
"pagination": {
  
  
"page": 0,
  
  
"limit": 0,
  
  
"total": 0,
  
  
"totalPages": 0
  
}
}

Samples


Bulk library sync feed

GET
/api/library/sync

Single paginated endpoint optimised for full-vault mirror clients (Obsidian plugin, CLIs). Returns BookSyncRecord[] bundling each organised book's metadata + a per-book progress aggregate (max % across devices + derived reading status). Optional ?since= filters to books whose metadata or progress changed after that time.

Parameters

Query Parameters

page

Page number

Type
integer
Minimum
1
Default
1
limit

Items per page

Type
integer
Minimum
1
Maximum
100
Default
20
since

ISO 8601 timestamp. When set, only return books whose metadata or progress changed after this time. Pass serverTime from the previous successful response.

Type
string
Format
"date-time"

Responses

Paginated sync records

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"status": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"isbn10": "string",
  
  
  
"isbn13": "string",
  
  
  
"publisher": "string",
  
  
  
"publishedYear": 0,
  
  
  
"language": "string",
  
  
  
"description": "string",
  
  
  
"coverUrl": "string",
  
  
  
"coverPath": "string",
  
  
  
"pageCount": 0,
  
  
  
"series": "string",
  
  
  
"seriesIndex": 0,
  
  
  
"genres": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"tags": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"hardcoverBookId": 0,
  
  
  
"hardcoverEditionId": 0,
  
  
  
"createdBy": "string",
  
  
  
"possibleDuplicateOf": "string",
  
  
  
"approvedAt": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string",
  
  
  
"files": [
  
  
  
  
{
  
  
  
  
  
"id": "string",
  
  
  
  
  
"format": "string",
  
  
  
  
  
"originalName": "string",
  
  
  
  
  
"fileSize": "string"
  
  
  
  
}
  
  
  
],
  
  
  
"uploader": {
  
  
  
  
"id": "string",
  
  
  
  
"label": "string"
  
  
  
},
  
  
  
"progress": {
  
  
  
  
"percentage": 0,
  
  
  
  
"status": "string",
  
  
  
  
"lastDevice": "string",
  
  
  
  
"lastTimestamp": 0,
  
  
  
  
"startedAt": "string",
  
  
  
  
"finishedAt": "string",
  
  
  
  
"pausedAt": "string",
  
  
  
  
"manuallySet": true,
  
  
  
  
"externallySet": true
  
  
  
}
  
  
}
  
],
  
"pagination": {
  
  
"page": 0,
  
  
"limit": 0,
  
  
"total": 0,
  
  
"totalPages": 0
  
},
  
"serverTime": "string"
}

Samples


Get library filter facets

GET
/api/library/facets

Returns distinct authors and genres from organized books for filter dropdowns

Responses

Distinct authors and genres

application/json
JSON
{
  
"authors": [
  
  
"string"
  
],
  
"genres": [
  
  
"string"
  
],
  
"languages": [
  
  
"string"
  
],
  
"series": [
  
  
"string"
  
],
  
"uploaders": [
  
  
{
  
  
  
"id": "string",
  
  
  
"label": "string"
  
  
}
  
]
}

Samples


Get library book

GET
/api/library/{id}

Retrieve a single organized book with its files

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Book with files

application/json
JSON
{
  
"id": "string",
  
"status": "string",
  
"title": "string",
  
"author": "string",
  
"isbn10": "string",
  
"isbn13": "string",
  
"publisher": "string",
  
"publishedYear": 0,
  
"language": "string",
  
"description": "string",
  
"coverUrl": "string",
  
"coverPath": "string",
  
"pageCount": 0,
  
"series": "string",
  
"seriesIndex": 0,
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"hardcoverBookId": 0,
  
"hardcoverEditionId": 0,
  
"createdBy": "string",
  
"possibleDuplicateOf": "string",
  
"approvedAt": "string",
  
"createdAt": "string",
  
"updatedAt": "string",
  
"files": [
  
  
{
  
  
  
"id": "string",
  
  
  
"format": "string",
  
  
  
"originalName": "string",
  
  
  
"fileSize": "string",
  
  
  
"storagePath": "string",
  
  
  
"checksum": "string"
  
  
}
  
],
  
"uploader": {
  
  
"id": "string",
  
  
"label": "string"
  
},
  
"progress": {
  
  
"percentage": 0,
  
  
"status": "string",
  
  
"lastDevice": "string",
  
  
"lastTimestamp": 0,
  
  
"startedAt": "string",
  
  
"finishedAt": "string",
  
  
"pausedAt": "string",
  
  
"manuallySet": true,
  
  
"externallySet": true
  
}
}

Samples


Update library book

PATCH
/api/library/{id}

Edit metadata fields on an organized book

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Request Body

application/json
JSON
{
  
"title": "string",
  
"author": "string",
  
"isbn10": "string",
  
"isbn13": "string",
  
"publisher": "string",
  
"publishedYear": 0,
  
"language": "string",
  
"description": "string",
  
"pageCount": 0,
  
"series": "string",
  
"seriesIndex": 0,
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"coverUrl": "string"
}

Responses

Updated book

application/json
JSON
{
  
"id": "string",
  
"status": "string",
  
"title": "string",
  
"author": "string",
  
"isbn10": "string",
  
"isbn13": "string",
  
"publisher": "string",
  
"publishedYear": 0,
  
"language": "string",
  
"description": "string",
  
"coverUrl": "string",
  
"coverPath": "string",
  
"pageCount": 0,
  
"series": "string",
  
"seriesIndex": 0,
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"hardcoverBookId": 0,
  
"hardcoverEditionId": 0,
  
"createdBy": "string",
  
"possibleDuplicateOf": "string",
  
"approvedAt": "string",
  
"createdAt": "string",
  
"updatedAt": "string"
}

Samples


Get reading progress for a book

GET
/api/library/{id}/progress

Returns reading progress across all devices by matching book file content hashes to KoReader document identifiers

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Reading progress entries for the book

application/json
JSON
{
  
"bookId": "string",
  
"progress": [
  
  
{
  
  
  
"document": "string",
  
  
  
"device": "string",
  
  
  
"deviceId": "string",
  
  
  
"progress": "string",
  
  
  
"percentage": 0,
  
  
  
"timestamp": 0
  
  
}
  
]
}

Samples


Refetch metadata from external sources

POST
/api/library/{id}/refetch

Delete existing non-file metadata candidates and re-fetch from Hardcover for an organized book. The book stays organized throughout.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Refetch enqueued

application/json
JSON
{
  
"status": "string",
  
"bookId": "string",
  
"searchQuery": "string"
}

Samples


Re-organize a library book

POST
/api/library/{id}/reorganize

Enqueue a BOOK_ORGANIZE job for an already-organized book so its files are moved to match updated metadata (author/title)

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Reorganize job enqueued

application/json
JSON
{
  
"message": "string",
  
"bookId": "string"
}

Samples


Apply refetched metadata to a library book

POST
/api/library/{id}/apply-metadata

Select metadata fields from refetched candidates and apply them to an organized book. Automatically enqueues a re-organize job to update file paths and re-embed EPUB metadata.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Request Body

application/json
JSON
{
  
"fields": {
  
  
"additionalProperties": {
  
  
  
"source": "string",
  
  
  
"value": "string"
  
  
}
  
}
}

Responses

Metadata applied and re-organize job enqueued

application/json
JSON
{
  
"id": "string",
  
"status": "string",
  
"title": "string",
  
"author": "string",
  
"isbn10": "string",
  
"isbn13": "string",
  
"publisher": "string",
  
"publishedYear": 0,
  
"language": "string",
  
"description": "string",
  
"coverUrl": "string",
  
"coverPath": "string",
  
"pageCount": 0,
  
"series": "string",
  
"seriesIndex": 0,
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"hardcoverBookId": 0,
  
"hardcoverEditionId": 0,
  
"createdBy": "string",
  
"possibleDuplicateOf": "string",
  
"approvedAt": "string",
  
"createdAt": "string",
  
"updatedAt": "string"
}

Samples


Clear the manual reading status override

DELETE
/api/library/{id}/reading-status

Remove any manual override and revert to the computed reading status from KoReader sync data.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Override cleared; returns the updated effective progress aggregate

application/json
JSON
{
  
"percentage": 0,
  
"status": "string",
  
"lastDevice": "string",
  
"lastTimestamp": 0,
  
"startedAt": "string",
  
"finishedAt": "string",
  
"pausedAt": "string",
  
"manuallySet": true,
  
"externallySet": true
}

Samples


Manually set reading status for a book

PATCH
/api/library/{id}/reading-status

Override the computed reading status with user-supplied values. Sticky against KoReader sync until the user clears the override via DELETE.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Request Body

application/json
JSON
{
  
"status": "string",
  
"startedAt": "string",
  
"finishedAt": "string",
  
"pausedAt": "string"
}

Responses

Override applied; returns the updated effective progress aggregate

application/json
JSON
{
  
"percentage": 0,
  
"status": "string",
  
"lastDevice": "string",
  
"lastTimestamp": 0,
  
"startedAt": "string",
  
"finishedAt": "string",
  
"pausedAt": "string",
  
"manuallySet": true,
  
"externallySet": true
}

Samples


Get library book cover

GET
/api/library/{id}/cover

Returns the cover image for an organized book, served from the library storage path. Supports ETag-based cache revalidation.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Cover image (JPEG, PNG, WebP, or GIF)

Samples


Download a book file

GET
/api/library/{id}/download/{fileId}

Streams the ebook file for download, identified by book ID and file ID. Sets Content-Disposition for browser download with the original filename.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"
fileId*

File UUID

Type
string
Required
Format
"uuid"

Responses

Ebook file binary stream

Samples


List inbox books

GET
/api/inbox

Paginated list of books in inbox or review status

Parameters

Query Parameters

page

Page number

Type
integer
Minimum
1
Default
1
limit

Items per page

Type
integer
Minimum
1
Maximum
100
Default
20
q

Full-text search query

Type
string
Max Length
500
Default
""
sort

Sort order for results

Type
string
Default
"detected_newest"

Responses

Paginated list of inbox books with files

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"status": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"isbn10": "string",
  
  
  
"isbn13": "string",
  
  
  
"publisher": "string",
  
  
  
"publishedYear": 0,
  
  
  
"language": "string",
  
  
  
"description": "string",
  
  
  
"coverUrl": "string",
  
  
  
"coverPath": "string",
  
  
  
"pageCount": 0,
  
  
  
"series": "string",
  
  
  
"seriesIndex": 0,
  
  
  
"genres": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"tags": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"hardcoverBookId": 0,
  
  
  
"hardcoverEditionId": 0,
  
  
  
"createdBy": "string",
  
  
  
"possibleDuplicateOf": "string",
  
  
  
"approvedAt": "string",
  
  
  
"createdAt": "string",
  
  
  
"updatedAt": "string",
  
  
  
"files": [
  
  
  
  
{
  
  
  
  
  
"id": "string",
  
  
  
  
  
"format": "string",
  
  
  
  
  
"originalName": "string",
  
  
  
  
  
"fileSize": "string"
  
  
  
  
}
  
  
  
],
  
  
  
"uploader": {
  
  
  
  
"id": "string",
  
  
  
  
"label": "string"
  
  
  
}
  
  
}
  
],
  
"pagination": {
  
  
"page": 0,
  
  
"limit": 0,
  
  
"total": 0,
  
  
"totalPages": 0
  
}
}

Samples


Get inbox count

GET
/api/inbox/count

Returns the number of books in inbox or review status

Responses

Inbox count

application/json
JSON
{
  
"count": 0
}

Samples


Inbox processing status

GET
/api/inbox/processing

Returns the current pipeline stage for books being processed (parsing, fetching metadata, organizing)

Responses

Map of bookId to processing stage

application/json
JSON
{
  
"processing": {
  
  
"additionalProperties": {
  
  
  
"stage": "string",
  
  
  
"label": "string"
  
  
}
  
}
}

Samples


Get inbox book

GET
/api/inbox/{id}

Retrieve a single inbox/review book with its files and metadata candidates

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Book with files and candidates

application/json
JSON
{
  
"id": "string",
  
"status": "string",
  
"title": "string",
  
"author": "string",
  
"isbn10": "string",
  
"isbn13": "string",
  
"publisher": "string",
  
"publishedYear": 0,
  
"language": "string",
  
"description": "string",
  
"coverUrl": "string",
  
"coverPath": "string",
  
"pageCount": 0,
  
"series": "string",
  
"seriesIndex": 0,
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"hardcoverBookId": 0,
  
"hardcoverEditionId": 0,
  
"createdBy": "string",
  
"possibleDuplicateOf": "string",
  
"approvedAt": "string",
  
"createdAt": "string",
  
"updatedAt": "string",
  
"possibleDuplicate": {
  
  
"id": "string",
  
  
"title": "string",
  
  
"author": "string",
  
  
"status": "string"
  
},
  
"files": [
  
  
{
  
  
  
"id": "string",
  
  
  
"format": "string",
  
  
  
"originalName": "string",
  
  
  
"fileSize": "string",
  
  
  
"inboxPath": "string",
  
  
  
"checksum": "string"
  
  
}
  
],
  
"candidates": [
  
  
{
  
  
  
"id": "string",
  
  
  
"source": "string",
  
  
  
"normalized": "string",
  
  
  
"confidence": "string",
  
  
  
"selectedFields": [
  
  
  
  
"string"
  
  
  
]
  
  
}
  
],
  
"uploader": {
  
  
"id": "string",
  
  
"label": "string"
  
}
}

Samples


Rescan inbox book metadata

PATCH
/api/inbox/{id}/rescan

Delete existing metadata candidates and re-fetch from external sources

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Rescan enqueued

application/json
JSON
{
  
"status": "string",
  
"bookId": "string",
  
"searchQuery": "string"
}

Samples


Get inbox book cover

GET
/api/inbox/{id}/cover

Returns the cover image for an inbox/review book. Tries EPUB extraction first, then falls back to proxying the coverUrl from metadata sources.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Cover image (JPEG, PNG, WebP, or GIF)

Samples


Upload ebook files

POST
/api/inbox/upload

Upload one or more ebook files (EPUB) to the inbox directory. Files are saved to disk; the file watcher picks them up for processing.

Request Body

multipart/form-data
object
string |array

One or more ebook files

Responses

Upload results with per-file success/error details

application/json
JSON
{
  
"uploaded": [
  
  
{
  
  
  
"filename": "string",
  
  
  
"size": 0
  
  
}
  
],
  
"errors": [
  
  
{
  
  
  
"filename": "string",
  
  
  
"error": "string"
  
  
}
  
]
}

Samples


Delete book

DELETE
/api/books/{id}

Delete a book and its associated files from the database and disk

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Book deleted

Samples


Approve book metadata

POST
/api/books/{id}/approve

Select metadata fields from candidates, mark book as organized, and enqueue file organization

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Request Body

application/json
JSON
{
  
"fields": {
  
  
"additionalProperties": {
  
  
  
"source": "string",
  
  
  
"value": "string"
  
  
}
  
}
}

Responses

Book approved and organize job enqueued

application/json
JSON
{
  
"id": "string",
  
"status": "string",
  
"title": "string",
  
"author": "string",
  
"genres": [
  
  
"string"
  
],
  
"tags": [
  
  
"string"
  
],
  
"createdAt": "string",
  
"updatedAt": "string"
}

Samples


Get metadata candidates

GET
/api/books/{id}/candidates

List metadata candidates fetched from external sources for a book

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Format
"uuid"

Responses

Book info with metadata candidates

application/json
JSON
{
  
"book": {
  
  
"id": "string",
  
  
"status": "string",
  
  
"title": "string",
  
  
"author": "string"
  
},
  
"candidates": [
  
  
{
  
  
  
"id": "string",
  
  
  
"source": "string",
  
  
  
"normalized": "string",
  
  
  
"confidence": "string",
  
  
  
"selectedFields": [
  
  
  
  
"string"
  
  
  
]
  
  
}
  
]
}

Samples


series


List all series

GET
/api/series

Returns distinct series names with book counts and cover art. Supports search filtering.

Parameters

Query Parameters

q

Filter series names (partial match)

Type
string
Max Length
500
Default
""

Responses

Series list

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"name": "string",
  
  
  
"bookCount": 0,
  
  
  
"coverUrl": "string",
  
  
  
"coverPath": "string",
  
  
  
"coverBookId": "string"
  
  
}
  
],
  
"total": 0
}

Samples


Get books in a series

GET
/api/series/{name}

Returns all books in the given series ordered by series_index (nulls last).

Parameters

Path Parameters

name*

Series name

Type
string
Required

Responses

Series detail with books

application/json
JSON
{
  
"series": "string",
  
"books": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"series": "string",
  
  
  
"seriesIndex": 0,
  
  
  
"coverUrl": "string",
  
  
  
"coverPath": "string",
  
  
  
"genres": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"tags": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"pageCount": 0,
  
  
  
"publishedYear": 0,
  
  
  
"files": [
  
  
  
  
{
  
  
  
  
  
"id": "string",
  
  
  
  
  
"format": "string",
  
  
  
  
  
"originalName": "string",
  
  
  
  
  
"fileSize": "string"
  
  
  
  
}
  
  
  
]
  
  
}
  
],
  
"total": 0
}

Samples


search


Search suggestions for command palette

GET
/api/search/suggest

Lightweight prefix search returning up to 8 results for autocomplete. Searches both organized and review books.

Parameters

Query Parameters

q*

Search prefix

Type
string
Required
Min Length
1
Max Length
500

Responses

Search suggestions

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"status": "string",
  
  
  
"coverUrl": "string"
  
  
}
  
]
}

Samples


dashboard


Get dashboard data

GET
/api/dashboard

Returns currently reading books, recently added, inbox count, library stats, and pipeline status

Responses

Dashboard data

application/json
JSON
{
  
"currentlyReading": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"coverPath": "string",
  
  
  
"percentage": 0,
  
  
  
"device": "string",
  
  
  
"lastRead": 0
  
  
}
  
],
  
"recentlyAdded": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"coverPath": "string",
  
  
  
"createdAt": "string"
  
  
}
  
],
  
"inboxCount": 0,
  
"stats": {
  
  
"totalBooks": 0,
  
  
"totalAuthors": 0,
  
  
"topGenre": "string",
  
  
"totalFileSize": 0,
  
  
"processingCount": 0
  
},
  
"pipeline": {
  
  
"additionalProperties": {
  
  
  
"waiting": 0,
  
  
  
"active": 0,
  
  
  
"completed": 0,
  
  
  
"failed": 0,
  
  
  
"delayed": 0
  
  
}
  
}
}

Samples


stats


Get reading statistics

GET
/api/stats

Returns reading analytics for the stats page: finished-book counts, genre distribution, reading streak, average finish time, yearly pages-read heatmap, books finished per month, reading velocity (7-day moving avg), top authors, days-to-finish histogram, and library growth.

Parameters

Query Parameters

year

Calendar year for the daily-pages heatmap (YYYY). Defaults to the current year.

Type
integer
Example2026
Minimum
1970
Maximum
2100

Responses

Reading statistics

application/json
JSON
{
  
"booksFinished": {
  
  
"allTime": 0,
  
  
"thisYear": 0,
  
  
"thisMonth": 0
  
},
  
"genreDistribution": [
  
  
{
  
  
  
"genre": "string",
  
  
  
"count": 0
  
  
}
  
],
  
"streak": {
  
  
"current": 0,
  
  
"longest": 0
  
},
  
"avgDaysToFinish": 0,
  
"pagesHeatmap": {
  
  
"year": 0,
  
  
"days": [
  
  
  
{
  
  
  
  
"day": "string",
  
  
  
  
"pages": 0
  
  
  
}
  
  
]
  
},
  
"finishedPerMonth": [
  
  
{
  
  
  
"month": "string",
  
  
  
"count": 0
  
  
}
  
],
  
"readingVelocity": [
  
  
{
  
  
  
"day": "string",
  
  
  
"avgPages": 0
  
  
}
  
],
  
"topAuthors": [
  
  
{
  
  
  
"author": "string",
  
  
  
"count": 0
  
  
}
  
],
  
"daysToFinishBuckets": [
  
  
{
  
  
  
"bucket": "string",
  
  
  
"count": 0
  
  
}
  
],
  
"libraryGrowth": [
  
  
{
  
  
  
"month": "string",
  
  
  
"cumulative": 0
  
  
}
  
]
}

Samples


Get reading status counts

GET
/api/reading-status/counts

Returns the count of organized books in each reading status (unread, reading, finished, paused).

Responses

Status counts

application/json
JSON
{
  
"unread": 0,
  
"reading": 0,
  
"finished": 0,
  
"paused": 0
}

Samples


List books by reading status

GET
/api/reading-status/{status}

Returns a paginated list of organized books filtered by the given reading status, with optional search and sorting.

Parameters

Path Parameters

status*

Reading status to filter by

Type
string
Required
Valid values
"unread""reading""finished""paused"

Query Parameters

page

Page number (1-based)

Type
integer
Minimum
1
Default
1
limit

Number of items per page

Type
integer
Minimum
1
Maximum
100
Default
20
sort

Sort field

Type
string
Default
"title"
order

Sort direction

Type
string
Default
"asc"
search

Full-text search query

Type
string
Max Length
500
Default
""

Responses

Paginated list of books with reading progress

application/json
JSON
{
  
"data": [
  
  
{
  
  
  
"id": "string",
  
  
  
"title": "string",
  
  
  
"author": "string",
  
  
  
"coverPath": "string",
  
  
  
"isbn13": "string",
  
  
  
"isbn10": "string",
  
  
  
"genres": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"pageCount": 0,
  
  
  
"percentage": 0,
  
  
  
"device": "string",
  
  
  
"lastReadAt": "string",
  
  
  
"readingStatus": "string"
  
  
}
  
],
  
"pagination": {
  
  
"page": 0,
  
  
"limit": 0,
  
  
"total": 0,
  
  
"totalPages": 0
  
}
}

Samples


Check service credentials

GET
/api/credentials/{service}

Check whether credentials are configured for a service (opds, kosync, or hardcover). Returns the username and timestamps if configured.

Parameters

Path Parameters

service*

Service name

Type
string
Required
Valid values
"opds""kosync""hardcover"

Responses

Credential status

application/json
JSON
{
  
"configured": true,
  
"service": "string",
  
"username": "string",
  
"createdAt": "string",
  
"updatedAt": "string"
}

Samples


Set service credentials

PUT
/api/credentials/{service}

Set or update credentials for a service. Passwords for opds/kosync are bcrypt-hashed. Hardcover tokens are sealed with reversible encryption.

Parameters

Path Parameters

service*

Service name

Type
string
Required
Valid values
"opds""kosync""hardcover"

Request Body

application/json
JSON
{
  
"username": "string",
  
"password": "string"
}

Responses

Credentials updated

application/json
JSON
{
  
"service": "string",
  
"username": "string",
  
"updated": true
}

Samples


Delete service credentials

DELETE
/api/credentials/{service}

Remove stored credentials for a service (opds, kosync, or hardcover).

Parameters

Path Parameters

service*

Service name

Type
string
Required
Valid values
"opds""kosync""hardcover"

Responses

Credentials deleted

application/json
JSON
{
  
"service": "string",
  
"deleted": true
}

Samples


Job queue status

GET
/api/jobs/status

Return job counts per queue (waiting, active, completed, failed, delayed, paused)

Responses

Queue status counts

application/json
JSON
{
  
"queues": {
  
  
"additionalProperties": {
  
  
  
"waiting": 0,
  
  
  
"active": 0,
  
  
  
"completed": 0,
  
  
  
"failed": 0,
  
  
  
"delayed": 0,
  
  
  
"paused": 0
  
  
}
  
}
}

Samples


List failed jobs

GET
/api/jobs/failed

Return failed jobs across all queues with job ID, queue name, error message, timestamps, and attempt count

Responses

List of failed jobs

application/json
JSON
{
  
"jobs": [
  
  
{
  
  
  
"id": "string",
  
  
  
"queueName": "string",
  
  
  
"name": "string",
  
  
  
"data": {
  
  
  
  
"additionalProperties": "string"
  
  
  
},
  
  
  
"error": "string",
  
  
  
"failedAt": 0,
  
  
  
"attemptsMade": 0,
  
  
  
"maxAttempts": 0
  
  
}
  
],
  
"total": 0
}

Samples


List jobs across all queues

GET
/api/jobs

Browse recent jobs across all queues with filtering by queue name and status. Supports pagination via page/pageSize query params.

Parameters

Query Parameters

queue

Filter by queue name (e.g. book-detected)

Type
string
status

Filter by job status

Type
string
Valid values
"completed""active""waiting""failed""delayed""paused"
page

Page number

Type
integer
Minimum
1
Default
1
pageSize

Items per page (max 100)

Type
integer
Minimum
1
Maximum
100
Default
20

Responses

Paginated list of jobs

application/json
JSON
{
  
"jobs": [
  
  
{
  
  
  
"id": "string",
  
  
  
"queueName": "string",
  
  
  
"name": "string",
  
  
  
"data": {
  
  
  
  
"additionalProperties": "string"
  
  
  
},
  
  
  
"status": "string",
  
  
  
"progress": 0,
  
  
  
"returnValue": "string",
  
  
  
"failedReason": "string",
  
  
  
"stacktrace": [
  
  
  
  
"string"
  
  
  
],
  
  
  
"attemptsMade": 0,
  
  
  
"maxAttempts": 0,
  
  
  
"timestamp": 0,
  
  
  
"processedOn": 0,
  
  
  
"finishedOn": 0,
  
  
  
"duration": 0
  
  
}
  
],
  
"total": 0,
  
"page": 0,
  
"pageSize": 0,
  
"totalPages": 0
}

Samples


Get job details

GET
/api/jobs/{id}

Return full details for a specific job including stack trace, duration, progress, timestamps, return value, and payload data. Searches all queues.

Parameters

Path Parameters

id*

Job ID

Type
string
Required
Min Length
1

Responses

Job details

application/json
JSON
{
  
"id": "string",
  
"queueName": "string",
  
"name": "string",
  
"data": {
  
  
"additionalProperties": "string"
  
},
  
"status": "string",
  
"progress": 0,
  
"returnValue": "string",
  
"failedReason": "string",
  
"stacktrace": [
  
  
"string"
  
],
  
"attemptsMade": 0,
  
"maxAttempts": 0,
  
"timestamp": 0,
  
"processedOn": 0,
  
"finishedOn": 0,
  
"duration": 0
}

Samples


Get job logs

GET
/api/jobs/{id}/logs

Return log lines stored via BullMQ job.log() for a specific job. Logs are stored in Redis per job and provide a timeline of job execution.

Parameters

Path Parameters

id*

Job ID

Type
string
Required
Min Length
1

Responses

Job logs

application/json
JSON
{
  
"jobId": "string",
  
"logs": [
  
  
"string"
  
],
  
"count": 0
}

Samples


Retry a failed job

POST
/api/jobs/{id}/retry

Retry a specific failed job by ID. Searches all queues for the job.

Parameters

Path Parameters

id*

Job ID to retry

Type
string
Required
Min Length
1

Responses

Job retried successfully

application/json
JSON
{
  
"success": true,
  
"jobId": "string",
  
"queueName": "string"
}

Samples


Pause a queue

POST
/api/jobs/queues/{name}/pause

Pause a specific queue by name. New jobs will not be processed until resumed.

Parameters

Path Parameters

name*

Queue name (e.g. book-detected)

Type
string
Required
Min Length
1

Responses

Queue paused

application/json
JSON
{
  
"success": true,
  
"queue": "string",
  
"paused": true
}

Samples


Resume a queue

POST
/api/jobs/queues/{name}/resume

Resume a paused queue. Jobs will begin processing again.

Parameters

Path Parameters

name*

Queue name

Type
string
Required
Min Length
1

Responses

Queue resumed

application/json
JSON
{
  
"success": true,
  
"queue": "string",
  
"paused": true
}

Samples


Clean failed jobs from a queue

POST
/api/jobs/queues/{name}/clean

Remove all failed jobs from a specific queue.

Parameters

Path Parameters

name*

Queue name

Type
string
Required
Min Length
1

Responses

Failed jobs cleaned

application/json
JSON
{
  
"success": true,
  
"queue": "string",
  
"removed": 0
}

Samples


Drain a queue

POST
/api/jobs/queues/{name}/drain

Remove all waiting and delayed jobs from a queue. Active jobs are not affected.

Parameters

Path Parameters

name*

Queue name

Type
string
Required
Min Length
1

Responses

Queue drained

application/json
JSON
{
  
"success": true,
  
"queue": "string"
}

Samples


Get Hardcover connection status

GET
/api/hardcover/status

Check whether a Hardcover credential is configured, verify the token with the Hardcover API, and return the connected username and last sync timestamp.

Responses

Connection status

application/json
JSON
{
  
"connected": true,
  
"username": "string",
  
"lastSyncAt": "string",
  
"error": "string"
}

Samples


Trigger Hardcover sync

POST
/api/hardcover/sync

Enqueue a job to synchronize reading progress and ratings with the Hardcover service. Requires a configured Hardcover credential.

Responses

Sync job enqueued

application/json
JSON
{
  
"message": "string"
}

Samples


List Hardcover sync log entries

GET
/api/hardcover/sync/log

Return recent Hardcover sync log entries joined with book titles, sorted by last synced timestamp descending.

Parameters

Query Parameters

limit

Maximum entries to return

Type
integer
Minimum
1
Maximum
100
Default
20

Responses

Array of sync log entries

application/json
JSON
[
  
{
  
  
"bookId": "string",
  
  
"bookTitle": "string",
  
  
"status": "string",
  
  
"progress": "string",
  
  
"rating": "string",
  
  
"syncedAt": "string"
  
}
]

Samples


Authenticate via KOReader headers

GET
/kosync/users/auth

KOReader sends credentials via x-auth-user (username) and x-auth-key (md5-hashed password) headers. Returns the userkey for subsequent sync requests. These non-standard headers are validated in the handler.

Responses

Authentication successful

application/json
JSON
{
  
"authorized": "string",
  
"userkey": "string"
}

Samples


Authenticate via JSON body

POST
/kosync/users/auth

Validate KoSync credentials provided as a JSON body. Returns the md5-hashed password as the userkey for subsequent sync requests.

Request Body

application/json
JSON
{
  
"username": "string",
  
"password": "string"
}

Responses

Authentication successful

application/json
JSON
{
  
"authorized": "string",
  
"userkey": "string"
}

Samples


Register a KoSync user (disabled)

POST
/kosync/users/create

KOReader calls this endpoint to register a new user. Registration is disabled in Libris — credentials must be set via the Libris dashboard. Always returns 409.

Request Body

application/json
JSON
{
  
"username": "string",
  
"password": "string"
}

Responses

Registration is disabled; set credentials in the Libris dashboard

Samples


Get reading progress

GET
/kosync/syncs/progress/{document}

Retrieve the most recent reading progress entry for a document identified by its hash. Returns 404 if no progress has been recorded for this document.

Parameters

Path Parameters

document*

Document hash (content or original)

Type
string
Required
Min Length
1

Responses

Reading progress

application/json
JSON
{
  
"document": "string",
  
"progress": "string",
  
"percentage": 0,
  
"device": "string",
  
"device_id": "string",
  
"timestamp": 0
}

Samples


Upsert reading progress

PUT
/kosync/syncs/progress

Create or update reading progress for a document/device pair. Also appends to the progress history table (fire-and-forget). Returns the persisted progress entry.

Request Body

application/json
JSON
{
  
"document": "string",
  
"progress": "string",
  
"device": "string",
  
"percentage": 0,
  
"device_id": "string"
}

Responses

Persisted reading progress

application/json
JSON
{
  
"document": "string",
  
"progress": "string",
  
"percentage": 0,
  
"device": "string",
  
"device_id": "string",
  
"timestamp": 0
}

Samples


OPDS root catalog

GET
/opds

Returns the top-level OPDS navigation feed with links to New Arrivals, All Books, Genres, and Series sub-catalogs, plus an OpenSearch descriptor link.

Responses

OPDS navigation feed (Atom XML)

application/atom+xml;profile=opds-catalog;kind=navigation
XML

Samples


List all books (OPDS)

GET
/opds/books

Returns a paginated OPDS acquisition feed of all organized books, sorted alphabetically by title. Supports page-based pagination via query parameter.

Parameters

Query Parameters

page

Page number (1-based)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed with book entries (Atom XML)

application/atom+xml;profile=opds-catalog;kind=acquisition
XML

Samples


Get a single book entry (OPDS)

GET
/opds/books/{id}

Returns an OPDS entry document for a single organized book, including metadata and acquisition links for available file formats.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Example"550e8400-e29b-41d4-a716-446655440000"
Format
"uuid"

Responses

OPDS entry document for the book (Atom XML)

application/atom+xml;type=entry;profile=opds-catalog
XML

Samples


Books by author (OPDS)

GET
/opds/authors/{slug}

Returns a paginated OPDS acquisition feed of books by a specific author, identified by a URL-friendly slug derived from the author name.

Parameters

Path Parameters

slug*

URL-friendly author slug

Type
string
Required
Min Length
1
Max Length
500

Query Parameters

page

Page number (1-based)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed of books by the author (Atom XML)

application/atom+xml;profile=opds-catalog;kind=acquisition
XML

Samples


List genres (OPDS)

GET
/opds/genres

Returns an OPDS navigation feed listing all genres found in organized books, each linking to a genre-specific acquisition feed.

Responses

OPDS navigation feed of genres (Atom XML)

application/atom+xml;profile=opds-catalog;kind=navigation
XML

Samples


Books by genre (OPDS)

GET
/opds/genres/{slug}

Returns a paginated OPDS acquisition feed of books in a specific genre, identified by a URL-friendly slug.

Parameters

Path Parameters

slug*

URL-friendly genre slug

Type
string
Required
Min Length
1
Max Length
500

Query Parameters

page

Page number (1-based)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed of books in the genre (Atom XML)

application/atom+xml;profile=opds-catalog;kind=acquisition
XML

Samples


List series (OPDS)

GET
/opds/series

Returns an OPDS navigation feed listing all book series found in organized books, each linking to a series-specific acquisition feed.

Responses

OPDS navigation feed of series (Atom XML)

application/atom+xml;profile=opds-catalog;kind=navigation
XML

Samples


Books in a series (OPDS)

GET
/opds/series/{name}

Returns a paginated OPDS acquisition feed of books in a specific series, ordered by series index.

Parameters

Path Parameters

name*

Series name

Type
string
Required
Min Length
1
Max Length
500

Query Parameters

page

Page number (1-based)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed of books in the series (Atom XML)

application/atom+xml;profile=opds-catalog;kind=acquisition
XML

Samples


New arrivals (OPDS)

GET
/opds/new

Returns a paginated OPDS acquisition feed of recently added books, sorted by creation date (newest first).

Parameters

Query Parameters

page

Page number (1-based)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed of new arrivals (Atom XML)

application/atom+xml;profile=opds-catalog;kind=acquisition
XML

Samples


Search books or get OpenSearch descriptor (OPDS)

GET
/opds/search

When called with a q query parameter, returns a paginated OPDS acquisition feed of matching books using full-text search. Without q, returns an OpenSearch description document that OPDS clients use for search discovery.

Parameters

Query Parameters

q

Search query. Omit to get the OpenSearch description document.

Type
string
Max Length
500
page

Page number (1-based, only used with q)

Type
integer
Example1
Minimum
1

Responses

OPDS acquisition feed of search results (Atom XML) or OpenSearch description (XML)

XML

Samples


Get book cover image (OPDS)

GET
/opds/covers/{id}

Returns the cover image for an organized book. Used by OPDS clients to display book thumbnails. Supports ETag-based cache revalidation.

Parameters

Path Parameters

id*

Book UUID

Type
string
Required
Example"550e8400-e29b-41d4-a716-446655440000"
Format
"uuid"

Responses

Cover image (JPEG, PNG, WebP, or GIF)

Samples


Download a book file (OPDS)

GET
/opds/download/{fileId}

Streams an ebook file for download, identified by its file ID. The file must belong to an organized book. Sets Content-Disposition for browser/e-reader download with the original filename.

Parameters

Path Parameters

fileId*

Book file UUID

Type
string
Required
Example"550e8400-e29b-41d4-a716-446655440000"
Format
"uuid"

Responses

Ebook file binary stream

Samples


Powered by VitePress OpenAPI