/api/v1 Reference

Bearer-token JSON API for the offline mobile/desktop client. Manage your token in Settings → Client API Access.

Settings
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
}
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
GET /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"
PUT /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"
GET /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"
POST /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.