/api/v1 Reference
Bearer-token JSON API for the offline mobile/desktop client. Manage your token in Settings → Client API Access.
Authentication
Every endpoint below (except this docs page) requires:
Authorization: Bearer <your-api-token>
Without a token, requests get 401 unauthorized.
If no token has been generated yet, the entire blueprint returns
503 api_disabled.
Pagination contract
All list endpoints share a single envelope. Default
page_size=50, max 200.
{
"items": [...],
"total": 42,
"page": 1,
"page_size": 50,
"total_pages": 1,
"has_more": false
}
Endpoints
/api/v1/auth/ping
token required
Verify bearer token + report server version and saved browse mode.
Response
{
"browse_mode": "metadata",
"ok": true,
"version": "x.y.z"
}
Example request
GET /api/v1/auth/ping
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/auth/ping"
/api/v1/library/publishers
token required
List publishers. Either ComicInfo metadata facet or top-level filesystem dirs.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | 1-indexed page number. |
page_size |
int | 50 | Items per page (max 200). |
mode |
str | (saved) | metadata | filesystem. Falls back to the saved preference. |
sort |
str | alpha | alpha | count (metadata mode only). |
Response
{
"has_more": false,
"items": [
{
"count": 42,
"has_thumbnail": true,
"name": "DC Comics",
"path": "/data/DC Comics",
"value": "DC Comics"
}
],
"mode": "filesystem",
"page": 1,
"page_size": 50,
"total": 12,
"total_pages": 1
}
Example request
GET /api/v1/library/publishers?mode=filesystem&page=1&page_size=20
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/publishers?mode=filesystem&page=1&page_size=20"
/api/v1/library/series
token required
List series under a publisher. Multi-volume series include a `volumes` array of subfolder names; single-volume series omit it. `count` is the recursive total across all volumes.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
publisher |
str | — | Required in filesystem mode (name or absolute path). |
q |
str | — | Search filter (metadata mode). |
sort |
str | alpha | alpha | count | year | recent. |
mode |
str | (saved) | metadata | filesystem. |
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"has_more": false,
"items": [
{
"count": 92,
"name": "Sabrina the Teenage Witch",
"path": "/data/Archie Comics/Sabrina the Teenage Witch",
"value": "Sabrina the Teenage Witch",
"volumes": [
"v1971",
"v1997"
]
}
],
"mode": "filesystem",
"page": 1,
"page_size": 50,
"total": 1,
"total_pages": 1
}
Example request
GET /api/v1/library/series?publisher=DC Comics&page=1&page_size=20
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/series?publisher=DC Comics&page=1&page_size=20"
/api/v1/library/issues
token required
List issues under a series. Items are progress-enriched.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
series |
str | — | Required. |
publisher |
str | — | Required in filesystem mode. |
volume |
str | — | Optional volume subfolder for nested series (filesystem mode). |
sort |
str | alpha | alpha | year | recent. |
mode |
str | (saved) | metadata | filesystem. |
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"has_more": false,
"items": [
{
"has_progress": true,
"id": 42,
"last_page": 5,
"name": "Batman 001 (2020).cbz",
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"size": 18234567
}
],
"mode": "filesystem",
"page": 1,
"page_size": 50,
"total": 1,
"total_pages": 1
}
Example request
GET /api/v1/library/issues?publisher=DC Comics&series=Batman&page=1&page_size=10
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/issues?publisher=DC Comics&series=Batman&page=1&page_size=10"
/api/v1/library/favorites
token required
Favorited publisher folders. `value` echoes back as `?publisher=` for /library/series.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"has_more": false,
"items": [
{
"created_at": "2026-04-25 10:00:00",
"name": "DC Comics",
"path": "/data/DC Comics",
"type": "publisher",
"value": "DC Comics"
}
],
"page": 1,
"page_size": 50,
"scope": "favorites",
"total": 1,
"total_pages": 1
}
Example request
GET /api/v1/library/favorites?page=1&page_size=20
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/favorites?page=1&page_size=20"
/api/v1/library/to-read
token required
User's 'want to read' list. Mixed file/folder rows; files carry id + progress. Folder rows that point at a multi-volume series include a `volumes` array (same semantics as /library/series). Folder rows that point at a volume leaf (e.g. .../Swamp Thing/v1985) additionally include `series` and `volume` so clients can render the row and drill in without parsing the path.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"has_more": false,
"items": [
{
"created_at": "...",
"has_progress": true,
"id": 42,
"last_page": 5,
"name": "Batman 001",
"path": "/data/.../Batman 001.cbz",
"type": "file",
"value": "Batman 001"
},
{
"created_at": "...",
"name": "Swamp Thing",
"path": "/data/DC Comics/Swamp Thing",
"type": "folder",
"value": "Swamp Thing",
"volumes": [
"v1971",
"v1985"
]
},
{
"created_at": "...",
"name": "Swamp Thing v1985",
"path": "/data/DC Comics/Swamp Thing/v1985",
"series": "Swamp Thing",
"type": "folder",
"value": "Swamp Thing v1985",
"volume": "v1985"
},
{
"created_at": "...",
"name": "Marvel",
"path": "/data/Marvel",
"type": "folder",
"value": "Marvel"
}
],
"page": 1,
"page_size": 50,
"scope": "to_read",
"total": 4,
"total_pages": 1
}
Example request
GET /api/v1/library/to-read?page=1&page_size=20
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/to-read?page=1&page_size=20"
/api/v1/library/recent
token required
CBZ/CBR files indexed in the last 30 days, inside enabled libraries.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"has_more": false,
"items": [
{
"added_at": "2026-04-20 09:33:11",
"has_progress": false,
"id": 42,
"last_page": null,
"name": "Batman 001 (2020).cbz",
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"size": 18234567,
"type": "file",
"value": "Batman 001 (2020).cbz"
}
],
"page": 1,
"page_size": 50,
"scope": "recent",
"total": 1,
"total_pages": 1
}
Example request
GET /api/v1/library/recent?page=1&page_size=20
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/library/recent?page=1&page_size=20"
/api/v1/issue/<file_id>
token required
Full ComicInfo metadata + saved reading position for a file_index row.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
file_id |
int | (path) | file_index.id integer. |
Response
{
"has_comicinfo": true,
"id": 42,
"metadata": {
"number": "1",
"publisher": "DC Comics",
"series": "Batman",
"title": "Origin",
"year": "2020"
},
"modified_at": 1700000000,
"name": "Batman 001 (2020).cbz",
"path": "/data/.../Batman 001 (2020).cbz",
"progress": {
"page_number": 5,
"total_pages": 32
},
"size": 18234567
}
Example request
GET /api/v1/issue/42
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/issue/42"
/api/v1/issue/<file_id>/cover
token required
JPEG of the first image inside the CBZ. Use ?size=N to clamp the long edge.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
file_id |
int | (path) | file_index.id. |
size |
int | 400 | Max long-edge px (64–2000). |
Response
binary/JPEG (image/jpeg) on success; 404 if cover unavailable.
Example request
GET /api/v1/issue/42/cover?size=400
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/issue/42/cover?size=400"
/api/v1/issue/<file_id>/download
token required
Stream the comic file. Supports HTTP Range for partial content.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
file_id |
int | (path) | file_index.id. |
Range |
header | — | Optional bytes=START-END for resumable downloads. |
Response
binary; 200 (full) or 206 (partial, when Range supplied).
Example request
GET /api/v1/issue/42/download
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/issue/42/download"
/api/v1/progress
token required
Saved reading position for a single comic, by absolute path.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path |
str | — | URL-encoded absolute comic_path. Required. |
Response
{
"page_number": 5,
"total_pages": 32,
"updated_at": "..."
}
Example request
GET /api/v1/progress?path=/data/DC Comics/Batman/Batman 001 (2020).cbz
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/progress?path=/data/DC Comics/Batman/Batman 001 (2020).cbz"
/api/v1/progress
token required
Save / update the reading position for a comic.
Request body
{
"page_number": 5,
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"time_spent": 120,
"total_pages": 32
}
Response
{
"page_number": 5,
"total_pages": 32,
"updated_at": "..."
}
Example request
PUT /api/v1/progress
Content-Type: application/json
{
"page_number": 5,
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"time_spent": 120,
"total_pages": 32
}
cURL
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"page_number": 5, "path": "/data/DC Comics/Batman/Batman 001 (2020).cbz", "time_spent": 120, "total_pages": 32}' \
"$BASE/api/v1/progress"
/api/v1/progress/since
token required
Reading positions changed at or after a unix timestamp. Paginated for resumable sync.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
ts |
int | 0 | Unix timestamp; rows with updated_at >= ts. |
page |
int | 1 | 1-indexed. |
page_size |
int | 50 | Max 200. |
Response
{
"count": 1,
"has_more": false,
"items": [
{
"comic_path": "...",
"page_number": 5,
"total_pages": 32,
"updated_at": "..."
}
],
"page": 1,
"page_size": 50,
"total": 1,
"total_pages": 1
}
Example request
GET /api/v1/progress/since?ts=1700000000&page=1&page_size=50
cURL
curl -H "Authorization: Bearer $TOKEN" \ "$BASE/api/v1/progress/since?ts=1700000000&page=1&page_size=50"
/api/v1/issues/read
token required
Mark an issue as read; records page_count and time_spent.
Request body
{
"page_count": 32,
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"time_spent": 1800
}
Response
{
"ok": true
}
Example request
POST /api/v1/issues/read
Content-Type: application/json
{
"page_count": 32,
"path": "/data/DC Comics/Batman/Batman 001 (2020).cbz",
"time_spent": 1800
}
cURL
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"page_count": 32, "path": "/data/DC Comics/Batman/Batman 001 (2020).cbz", "time_spent": 1800}' \
"$BASE/api/v1/issues/read"
CLU /api/v1 — generated from routes/api_v1_docs.py.