Skip to main content

API Documentation

Codex provides a comprehensive RESTful API for managing your digital library. This guide covers authentication, endpoints, and how to use the interactive API documentation.

Base URL​

All API endpoints are prefixed with /api/v1:

http://localhost:8080/api/v1

Interactive API Documentation​

Codex includes built-in interactive API documentation powered by Scalar (OpenAPI).

Enabling API Docs​

API documentation is disabled by default. Enable it in your configuration:

api:
enable_api_docs: true
api_docs_path: "/docs" # Optional, defaults to /docs

Or via environment variable:

CODEX_API__ENABLE_API_DOCS=true

Accessing API Docs​

Once enabled, access the interactive documentation at:

http://localhost:8080/docs

Using the API Documentation​

  1. Explore Endpoints: Browse all available API endpoints organized by category
  2. Try It Out: Click on any endpoint to make live requests
  3. Authenticate: Use the authentication section to enter your JWT token
  4. View Schemas: Explore request/response schemas and data models

Exporting OpenAPI Specification​

Export the OpenAPI spec for client generation or documentation:

# JSON format
codex openapi --output openapi.json --format json

# YAML format
codex openapi --output openapi.yaml --format yaml

:::tip Production Note Disable API documentation in production environments for security:

api:
enable_api_docs: false

:::

Authentication​

Codex supports multiple authentication methods.

The primary authentication method for web clients.

1. Login to Get Token​

curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "your-password"
}'

Response:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400,
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "admin",
"email": "admin@example.com",
"role": "admin"
}
}

2. Use Token in Requests​

Include the token in the Authorization header:

curl -H "Authorization: Bearer YOUR_TOKEN_HERE" \
http://localhost:8080/api/v1/libraries

API Keys​

For automation and service-to-service communication.

Create an API Key​

curl -X POST http://localhost:8080/api/v1/api-keys \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My Script Key",
"permissions": ["libraries-read", "books-read", "pages-read"]
}'

Response:

{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "My Script Key",
"key": "codex_abc12345_xyzSecretPart123456",
"key_prefix": "abc12345",
"permissions": ["libraries-read", "books-read", "pages-read"],
"created_at": "2024-01-15T10:30:00Z"
}
warning

The full API key is only shown once! Store it securely.

Use API Key​

curl -H "X-API-Key: codex_abc12345_xyzSecretPart123456" \
http://localhost:8080/api/v1/libraries

Or as a Bearer token:

curl -H "Authorization: Bearer codex_abc12345_xyzSecretPart123456" \
http://localhost:8080/api/v1/libraries

HTTP Basic Auth​

For simple clients and legacy systems:

curl -u "username:password" http://localhost:8080/api/v1/libraries

API Endpoints​

Setup (First Run)​

MethodEndpointDescription
GET/setup/statusCheck if initial setup is needed
POST/setup/initializeCreate the initial admin user

Authentication​

MethodEndpointDescription
POST/auth/loginUser login
POST/auth/registerUser registration
POST/auth/logoutUser logout
GET/auth/meGet current user info
POST/auth/verify-emailVerify email token
POST/auth/resend-verificationResend verification email

Libraries​

MethodEndpointDescription
GET/librariesList all libraries
POST/librariesCreate a library
GET/libraries/{id}Get library details
PUT/libraries/{id}Update a library
DELETE/libraries/{id}Delete a library
GET/libraries/{id}/thumbnailGet library cover image

Create Library Example​

curl -X POST http://localhost:8080/api/v1/libraries \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My Comics",
"path": "/library/comics",
"scanning_config": {
"enabled": true,
"cron_schedule": "0 0 * * *",
"default_mode": "normal",
"scan_on_start": true
}
}'

Scanning​

MethodEndpointDescription
POST/libraries/{id}/scanStart a library scan
GET/libraries/{id}/scan-statusGet current scan status
POST/libraries/{id}/scan/cancelCancel running scan
GET/scans/activeList all active scans
GET/scans/streamSSE: Scan progress events

Trigger Scan Example​

# Normal scan (only new/changed files)
curl -X POST "http://localhost:8080/api/v1/libraries/{id}/scan?mode=normal" \
-H "Authorization: Bearer $TOKEN"

# Deep scan (re-analyze all files)
curl -X POST "http://localhost:8080/api/v1/libraries/{id}/scan?mode=deep" \
-H "Authorization: Bearer $TOKEN"

Series​

MethodEndpointDescription
GET/seriesList all series
POST/series/listAdvanced filtering with conditions
POST/series/searchFull-text search
GET/series/in-progressSeries with in-progress books
GET/series/recently-addedRecently added series
GET/series/recently-updatedRecently updated series
GET/series/{id}Get series details
GET/series/{id}/booksGet books in series
GET/series/{id}/thumbnailGet series cover
POST/series/{id}/analyzeAnalyze all books in series
POST/series/{id}/readMark series as read
POST/series/{id}/unreadMark series as unread

Series Sorting​

Use the sort parameter with format field,direction. Available fields: name, date_added, date_updated, release_date, date_read, book_count, file_size, page_count.

curl "http://localhost:8080/api/v1/series?sort=date_added,desc" \
-H "Authorization: Bearer $TOKEN"

Books​

MethodEndpointDescription
GET/booksList all books
POST/books/listAdvanced filtering with conditions
GET/books/{id}Get book details
GET/books/{id}/thumbnailGet book cover
POST/books/{id}/analyzeTrigger book analysis
GET/books/in-progressGet books currently being read
GET/books/on-deckNext unread book in started series
GET/books/recently-addedGet recently added books
GET/books/recently-readGet recently read books

On Deck​

The "On Deck" endpoint returns the next unread book in series where you have completed at least one book but have no books currently in progress.

curl "http://localhost:8080/api/v1/books/on-deck" \
-H "Authorization: Bearer $TOKEN"

Pages​

MethodEndpointDescription
GET/books/{id}/pagesList pages in a book
GET/books/{book_id}/pages/{page_number}Get page image

Page Image Parameters​

ParameterTypeDescription
widthintegerMaximum width for resizing
heightintegerMaximum height for resizing
formatstringOutput format: jpeg, png, webp

Example:

curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/books/{id}/pages/1?width=800&format=webp"

Reading Progress​

MethodEndpointDescription
GET/books/{id}/progressGet reading progress
PUT/books/{id}/progressUpdate reading progress
DELETE/books/{id}/progressClear reading progress
GET/progressGet all user progress
GET/progress/currently-readingGet currently reading books
POST/books/{id}/readMark book as read
POST/books/{id}/unreadMark book as unread

Update Progress Example​

curl -X PUT http://localhost:8080/api/v1/books/{id}/progress \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"current_page": 15,
"is_completed": false
}'

Users (Admin Only)​

MethodEndpointDescription
GET/usersList all users
POST/usersCreate a user
GET/users/{id}Get user details
PUT/users/{id}Update a user
DELETE/users/{id}Delete a user

API Keys​

MethodEndpointDescription
GET/api-keysList your API keys
POST/api-keysCreate an API key
GET/api-keys/{id}Get API key details
PUT/api-keys/{id}Update an API key
DELETE/api-keys/{id}Revoke an API key

Tasks​

MethodEndpointDescription
GET/tasksList background tasks
GET/tasks/{id}Get task details
POST/tasks/{id}/cancelCancel a running task
GET/tasks/statsGet task statistics
GET/tasks/streamSSE: Task progress events

Duplicates​

MethodEndpointDescription
GET/duplicatesList duplicate book groups
POST/duplicates/scanScan for duplicates
DELETE/duplicates/{id}Dismiss a duplicate group

User Preferences​

Per-user settings (theme, language, reader options). See User Management for details.

MethodEndpointDescription
GET/user/preferencesList all preferences
PUT/user/preferences/{key}Set a preference
DELETE/user/preferences/{key}Reset to default

Settings (Admin Only)​

MethodEndpointDescription
GET/admin/settingsList all settings
GET/admin/settings/{key}Get a specific setting
PUT/admin/settings/{key}Update a setting
POST/admin/settings/bulkBulk update settings
POST/admin/settings/{key}/resetReset to default
GET/admin/settings/{key}/historyGet setting change history

Filesystem (Admin Only)​

MethodEndpointDescription
GET/filesystem/browseBrowse server directories
GET/filesystem/drivesList available drives (Windows)

Health & Metrics​

MethodEndpointDescription
GET/healthHealth check
GET/metricsServer metrics

Real-Time Events (SSE)​

Codex uses Server-Sent Events (SSE) for real-time updates.

Entity Events Stream​

curl -H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream" \
http://localhost:8080/api/v1/events/stream

Event types:

EventDescription
book_createdNew book added
book_updatedBook metadata changed
book_deletedBook removed
series_createdNew series discovered
series_updatedSeries metadata changed
series_deletedSeries removed
library_createdNew library added
library_updatedLibrary settings changed
cover_updatedThumbnail regenerated

Event format:

event: book_created
data: {"type":"book_created","book_id":"uuid","series_id":"uuid","library_id":"uuid","timestamp":"2024-01-15T10:30:00Z"}

Task Progress Stream​

curl -H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream" \
http://localhost:8080/api/v1/tasks/stream

Event format:

event: task_progress
data: {"task_id":"uuid","task_type":"scan_library","status":"running","progress":{"current":25,"total":100,"message":"Scanning file 25/100"}}

SSE Keep-Alive​

SSE connections send a keep-alive comment every 15 seconds:

: keep-alive

Pagination​

List endpoints support pagination with the following conventions:

Query Parameters​

All endpoints (GET and POST) use query parameters for pagination:

ParameterDefaultMaxDescription
page1-Page number (1-indexed)
pageSize50500Items per page

GET Requests​

curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/books?page=2&pageSize=25"

POST Requests (Filtering Endpoints)​

POST endpoints like /api/v1/books/list and /api/v1/series/list use:

  • Query parameters for pagination (page, pageSize, sort)
  • Request body for filter criteria only
curl -X POST "http://localhost:8080/api/v1/series/list?page=1&pageSize=25&sort=name,asc" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"condition": { "genre": { "operator": "is", "value": "Action" } },
"fullTextSearch": "batman"
}'

Response Format​

All paginated responses use camelCase and include HATEOAS navigation links:

{
"data": [...],
"page": 2,
"pageSize": 25,
"total": 150,
"totalPages": 6,
"links": {
"self": "/api/v1/series/list?page=2&pageSize=25",
"first": "/api/v1/series/list?page=1&pageSize=25",
"prev": "/api/v1/series/list?page=1&pageSize=25",
"next": "/api/v1/series/list?page=3&pageSize=25",
"last": "/api/v1/series/list?page=6&pageSize=25"
}
}
note

GET endpoints also support page_size (snake_case) for backwards compatibility, but pageSize (camelCase) is preferred for consistency.

Filtering & Sorting​

Common Query Parameters​

ParameterDescriptionExample
library_idFilter by librarylibrary_id=uuid
series_idFilter by seriesseries_id=uuid
sortSort fieldsort=created_at
orderSort directionorder=desc

Sort Fields​

Books: title, number, file_size, page_count, created_at, modified_at

Series: name, date_added, date_updated, release_date, date_read, book_count, file_size, filename, page_count

Example:

curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/books?library_id=uuid&sort=title&order=asc"

Advanced Filtering​

Use POST /series/list or POST /books/list for condition-based filtering.

Condition Structure​

Filters use a tree structure with allOf (AND) and anyOf (OR) combinators.

Request URL with pagination:

POST /api/v1/series/list?page=1&pageSize=20&sort=name,asc

Request body with filter criteria:

{
"condition": {
"allOf": [
{ "genre": { "operator": "is", "value": "Action" } },
{ "genre": { "operator": "isNot", "value": "Horror" } }
]
},
"fullTextSearch": "batman"
}

Operators​

OperatorDescription
isEquals value
isNotNot equals value
isNullField is null
isNotNullField has value
containsContains substring
beginsWithStarts with

Filter Fields​

Series: libraryId, genre, tag, status, publisher, language, name, readStatus

Books: libraryId, seriesId, genre, tag, title, readStatus, hasError

Example: Genre filter with exclusion​

curl -X POST "http://localhost:8080/api/v1/series/list?page=1&pageSize=20" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"condition": {
"allOf": [
{ "genre": { "operator": "is", "value": "Action" } },
{ "genre": { "operator": "isNot", "value": "Horror" } }
]
}
}'

See the Filtering & Search guide for more examples.

Error Responses​

All errors follow a consistent format:

{
"error": "NotFound",
"message": "Book not found",
"details": null
}

HTTP Status Codes​

CodeMeaningDescription
200OKRequest successful
201CreatedResource created
204No ContentSuccess, no response body
400Bad RequestInvalid request data
401UnauthorizedAuthentication required
403ForbiddenInsufficient permissions
404Not FoundResource not found
409ConflictResource conflict
500Internal ErrorServer error

Permissions​

API endpoints require specific permissions. Names on the wire are kebab-case (the colon form libraries:read is also accepted in requests):

PermissionDescription
libraries-readView libraries
libraries-writeCreate/update libraries
libraries-deleteDelete libraries
series-readView series, want-to-read, recommendations, exports
series-writeUpdate series
series-deleteDelete series
books-readView books
books-writeUpdate book metadata
books-deleteDelete books
collections-readBrowse collections
collections-writeManage collections
collections-deleteDelete collections
read-lists-readBrowse read lists
read-lists-writeManage read lists
read-lists-deleteDelete read lists
pages-readView page images
progress-readView reading progress, history, and stats
progress-writeUpdate progress, mark read/unread, record sessions
users-readView users (admin)
users-writeManage users (admin)
users-deleteDelete users (admin)
api-keys-readView API keys
api-keys-writeManage API keys
api-keys-deleteDelete API keys
tasks-readView tasks
tasks-writeManage tasks
plugins-manageManage metadata plugins (admin)
system-healthView metrics
system-adminFull admin access

Reading progress endpoints are gated on the progress permissions, not the book permissions: a key needs progress-write to update progress or mark books read, and progress-read alone is enough for a stats-only integration against /api/v1/reading-stats.

See Permissions & Roles for the full model.

Code Examples​

JavaScript/TypeScript​

const API_URL = 'http://localhost:8080/api/v1';

// Login
const loginResponse = await fetch(`${API_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'password' })
});
const { access_token } = await loginResponse.json();

// Get libraries
const libraries = await fetch(`${API_URL}/libraries`, {
headers: { 'Authorization': `Bearer ${access_token}` }
}).then(r => r.json());

// Subscribe to events
const eventSource = new EventSource(
`${API_URL}/events/stream`,
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);

eventSource.onmessage = (event) => {
console.log('Event:', JSON.parse(event.data));
};

Python​

import requests

API_URL = 'http://localhost:8080/api/v1'

# Login
response = requests.post(f'{API_URL}/auth/login', json={
'username': 'admin',
'password': 'password'
})
token = response.json()['access_token']

headers = {'Authorization': f'Bearer {token}'}

# Get libraries
libraries = requests.get(f'{API_URL}/libraries', headers=headers).json()

# Create a library
new_library = requests.post(f'{API_URL}/libraries', headers=headers, json={
'name': 'My Library',
'path': '/media/comics'
}).json()

cURL​

# Login and save token
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}' | jq -r '.access_token')

# List libraries
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/api/v1/libraries

# Create library
curl -X POST http://localhost:8080/api/v1/libraries \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Comics","path":"/media/comics"}'

# Get book cover
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/api/v1/books/{id}/thumbnail > cover.jpg

Next Steps​