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": ["LibrariesRead", "BooksRead", "PagesRead"]
}'

Response:

{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "My Script Key",
"key": "codex_abc12345_xyzSecretPart123456",
"key_prefix": "abc12345",
"permissions": ["LibrariesRead", "BooksRead", "PagesRead"],
"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:

PermissionDescription
LibrariesReadView libraries
LibrariesWriteCreate/update libraries
LibrariesDeleteDelete libraries
SeriesReadView series
SeriesWriteUpdate series
SeriesDeleteDelete series
BooksReadView books
BooksWriteUpdate books/progress
BooksDeleteDelete books
PagesReadView page images
UsersReadView users (admin)
UsersWriteManage users (admin)
UsersDeleteDelete users (admin)
ApiKeysReadView API keys
ApiKeysWriteManage API keys
ApiKeysDeleteDelete API keys
TasksReadView tasks
TasksWriteManage tasks
SystemHealthView metrics
SystemAdminFull admin access

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​