Files
bookhoard/docs/developer/openapi.yaml
T
John O'Keefe 983980d07a bruno+docs: status asserts on generated mirrors, OpenAPI spec, safe negative scenarios
Three follow-ups from the smoke run, all additive:

1. Status asserts: bruno_gen.go parses each doc's documented success
   status (## Response (2NN), 'Success is **201**', '**204 No Content**')
   and emits a runtime tests script (expect(res.status).to.eql(N)) on
   148 of 191 mirrors. GETs default to 200 (uniform across this API);
   mutating verbs stay assert-less unless documented — no guessed
   asserts. Verified live: asserts execute and fail loudly (deliberate
   999 probe), pass on real responses.

2. OpenAPI: the same -update run now also writes
   docs/developer/openapi.yaml (141 paths, tags from docs areas,
   security schemes per auth label, request examples literal, no
   invented schemas — the docs site remains the shape reference).
   Verify mode fails when the file is missing.

3. Scenarios: 7 safe negative scenarios rebuilt (auth registration
   matrix 409/403/400, invalid-uuid 400, unknown 404 x2, invalid range
   400) — all no-mutation, repeatable, run via bru: 7/7 tests pass.
   These replace a fraction of the deleted broken suite; mutations-
   heavy scenarios stay out until a design for setup chains exists.

created_at RFC3339 deliberately NOT done — it is the one item that
would break things (Android parses current formats; plan reserves it
as a compat decision).bru run of mutating mirrors also proven to touch
live data (a 'To Read' collection was created and deleted in testing);
only id-less GET mirrors and negative scenarios are safe for blanket
runs.

make test green; generation idempotent (byte-identical re-runs);
no stray smoke rows in users.
2026-10-24 19:20:13 -04:00

2422 lines
61 KiB
YAML

openapi: 3.0.3
info:
title: Bookhoard API
version: '2026.10.24'
description: |
Generated from the canonical API docs (docs/developer/api/**) by
internal/docs (go test ./internal/docs -run TestBrunoMirrorsDocs -update).
The docs site is the shape reference; this file lists the surface.
servers:
- url: /
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
paths:
"/api/admin/hash-conflicts":
get:
tags: [admin]
summary: "Hash Conflicts (API)"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/analytics/device-usage":
get:
tags: [analytics]
summary: "Get Device Usage"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/analytics/popular-books":
get:
tags: [analytics]
summary: "Get Popular Books"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/analytics/reading-stats":
get:
tags: [analytics]
summary: "Get Reading Statistics"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/auth/login":
post:
tags: [authentication]
summary: "Login User"
security: []
requestBody:
content:
application/json:
example: |-
{
"login": "user@example.com",
"password": "SecureP@ss123!"
}
responses:
'200':
description: OK
"/api/auth/logout":
post:
tags: [authentication]
summary: "Logout User"
security: []
responses:
'200':
description: OK
"/api/auth/password":
put:
tags: [authentication]
summary: "Change Password"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"current_password": "OldPassword123!",
"new_password": "NewSecureP@ss123!",
"confirm_password": "NewSecureP@ss123!"
}
responses:
'200':
description: OK
"/api/auth/password-rules":
get:
tags: [authentication]
summary: "Password Rules"
security: []
responses:
'200':
description: OK
"/api/auth/profile":
delete:
tags: [authentication]
summary: "Delete User"
security:
- bearerAuth: []
responses:
'200':
description: OK
get:
tags: [authentication]
summary: "Get Current User Profile"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [authentication]
summary: "Update Profile"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"username": "newusername",
"email": "newemail@example.com",
"first_name": "John",
"last_name": "Smith",
"theme": "dracula"
}
responses:
'200':
description: OK
"/api/auth/refresh":
post:
tags: [authentication]
summary: "Refresh Token"
security: []
requestBody:
content:
application/json:
example: |-
{
"refresh_token": "d4f5g6h7..."
}
responses:
'200':
description: OK
"/api/auth/register":
post:
tags: [authentication]
summary: "Register User"
security: []
requestBody:
content:
application/json:
example: |-
{
"email": "user@example.com",
"username": "john",
"password": "SecureP@ss123!",
"first_name": "John",
"last_name": "Doe"
}
responses:
'201':
description: Created
"/api/auth/users":
get:
tags: [authentication]
summary: "List Users"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/auth/users/{id}/max-devices":
put:
tags: [authentication]
summary: "Update User Max Devices"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"max_devices": 15
}
responses:
'200':
description: OK
"/api/books/match":
get:
tags: [book-matching]
summary: "Get Book Matches"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/collections":
get:
tags: [collections]
summary: "List Collections"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [collections]
summary: "Create Collection"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "To Read",
"description": "Books I want to read soon",
"color": "#00FF00",
"icon": "📖",
"collection_type": "static",
"auto_assign_rules": [],
"view_settings": { "kobo": { "view_mode": "grid" } }
}
responses:
'200':
description: Success
"/api/collections/bulk-add-books":
post:
tags: [collections]
summary: "Bulk Add Books"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"operations": [
{
"collection_id": "550e8400-e29b-41d4-a716-446655440000",
"book_ids": [
"660e8400-e29b-41d4-a716-446655440001"
]
}
]
}
responses:
'200':
description: Success
"/api/collections/preview":
post:
tags: [collections]
summary: "Preview Collection"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000",
"rules": [],
"manual_book_ids": [],
"limit": 20
}
responses:
'200':
description: Success
"/api/collections/test-rules":
post:
tags: [collections]
summary: "Test Rule"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"rules": [
{
"field": "genre",
"operator": "equals",
"value": "Science Fiction"
},
{
"field": "author",
"operator": "contains",
"value": "Asimov"
}
]
}
responses:
'200':
description: OK
"/api/collections/{id}":
delete:
tags: [collections]
summary: "Delete Collection"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [collections]
summary: "Get Collection"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [collections]
summary: "Update Collection"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "To Read (2026)",
"description": "Updated description",
"color": "#33CCFF",
"icon": "📚",
"auto_assign_rules": [],
"view_settings": { "hide_finished": true },
"hide_finished": ["true"],
"show_up_next": ["true"]
}
responses:
'200':
description: Success
"/api/collections/{id}/books":
get:
tags: [collections]
summary: "Get Book Collections"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [collections]
summary: "Bulk Assign Books"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"book_ids": [
"660e8400-e29b-41d4-a716-446655440000",
"770e8400-e29b-41d4-a716-446655440000",
"880e8400-e29b-41d4-a716-446655440000"
]
}
responses:
'204':
description: No Content
"/api/collections/{id}/books/bulk-remove":
post:
tags: [collections]
summary: "Bulk Remove Books"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"book_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
]
}
responses:
'200':
description: Success
"/api/collections/{id}/items/order":
put:
tags: [collections]
summary: "Reorder Collection Items"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"item_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
]
}
responses:
'200':
description: Success
"/api/collections/{id}/rules":
post:
tags: [collections]
summary: "Add Auto-Assign Rule"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"field": "genre",
"operator": "equals",
"value": "Science Fiction",
"priority": 1,
"enabled": true
}
responses:
'201':
description: Created
"/api/collections/{id}/rules/{ruleId}":
delete:
tags: [collections]
summary: "Remove Auto-Assign Rule"
security:
- bearerAuth: []
responses:
'204':
description: No Content
put:
tags: [collections]
summary: "Update Collection Rule"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"enabled": false
}
responses:
'200':
description: Success
"/api/conflicts":
get:
tags: [conflicts]
summary: "List Conflicts"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/conflicts/bulk-dismiss":
post:
tags: [conflicts]
summary: "Bulk Dismiss Conflicts"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"conflict_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
]
}
responses:
'200':
description: OK
"/api/conflicts/bulk-resolve":
post:
tags: [conflicts]
summary: "Bulk Resolve Conflicts"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"conflict_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
],
"strategy": "highest_progress"
}
responses:
'200':
description: OK
"/api/conflicts/dismiss-all":
post:
tags: [conflicts]
summary: "Dismiss All Resolved"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/conflicts/{id}":
delete:
tags: [conflicts]
summary: "Delete Conflict"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [conflicts]
summary: "Get Conflict Details"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/conflicts/{id}/resolve":
post:
tags: [conflicts]
summary: "Resolve Conflict"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"winner": "kobo"
}
responses:
'200':
description: OK
"/api/dashboard/preferences":
get:
tags: [dashboard]
summary: "Get Dashboard Preferences"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [dashboard]
summary: "Update Dashboard Preferences"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000",
"hidden_collections": ["not-started"],
"collection_order": ["recently-added", "continue-reading", "recently-read"],
"items_per_section": 20
}
responses:
'200':
description: Success
"/api/dashboard/restore-system-collection":
post:
tags: [dashboard]
summary: "Restore System Collection"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"collection_name": "Continue Reading",
"reset_type": "full"
}
responses:
'200':
description: Success
"/api/dashboard/sections":
get:
tags: [dashboard]
summary: "Get Dashboard Sections"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices":
get:
tags: [devices]
summary: "List User Devices"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/approve/{registration_id}":
get:
tags: [devices]
summary: "Approve Device Registration"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/pending":
get:
tags: [devices]
summary: "List Pending Device Registrations:\u003c|end|\u003e\u003c|start|\u003e\u003c|start|\u003eassistant to=edit\u003c|channel|\u003eanalysis \u003c|constrain|\u003exml\u003c|message|\u003e\u003crfl:parameter name=\"path\"\u003e"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/register":
post:
tags: [devices]
summary: "Register Device"
security: []
requestBody:
content:
application/json:
example: |-
{
"device_name": "My Kobo Clara",
"device_type": "kobo",
"device_identifier": "hardware-specific-id"
}
responses:
'201':
description: Created
"/api/devices/register/status":
post:
tags: [devices]
summary: "Get Device / Check Registration Status"
security: []
requestBody:
content:
application/json:
example: |-
{
"registration_id": "registration-uuid"
}
responses:
'200':
description: OK
"/api/devices/reject/{registration_id}":
post:
tags: [devices]
summary: "Reject Device Registration"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/{deviceId}/sync/link-book":
post:
tags: [book-matching]
summary: "Link Book"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"device_file": {
"file_path": "/books/hobbit.epub",
"sha256": "abc123...",
"title": "The Hobbit"
},
"media_item_id": "550e8400-e29b-41d4-a716-446655440000",
"confidence_score": 1.0
}
responses:
'200':
description: OK
post:
tags: [devices]
summary: "Link Book"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"device_file": {
"file_path": "/books/1984.epub",
"sha256": "abc123...",
"title": "1984"
},
"media_item_id": "550e8400-e29b-41d4-a716-446655440000",
"confidence_score": 0.95
}
responses:
'200':
description: Success
"/api/devices/{deviceId}/sync/unlinked-books":
get:
tags: [book-matching]
summary: "Get Unlinked Books"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/{id}":
delete:
tags: [devices]
summary: "Delete Device"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [devices]
summary: "Get Device"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [devices]
summary: "Update Device"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"device_name": "My Kobo Clara",
"sync_enabled": true,
"auto_sync": true,
"sync_frequency_minutes": 60
}
responses:
'200':
description: OK
"/api/devices/{id}/collections":
get:
tags: [devices]
summary: "Get Device Collection Mappings"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [collections]
summary: "Create Shelf Mapping"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"collection_id": "550e8400-e29b-41d4-a716-446655440000",
"device_shelf_name": "Sci-Fi",
"sync_direction": "bidirectional"
}
responses:
'201':
description: Created
"/api/devices/{id}/collections/{collectionId}":
delete:
tags: [collections]
summary: "Delete Shelf Mapping"
security:
- bearerAuth: []
responses:
'204':
description: No Content
put:
tags: [devices]
summary: "Update Device Collection Mapping"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"device_shelf_name": "Kobo",
"sync_direction": "bidirectional"
}
responses:
'200':
description: Success
"/api/devices/{id}/file-aliases":
get:
tags: [book-matching]
summary: "Get Device File Aliases"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [book-matching]
summary: "Create Device File Alias"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"media_item_id": "550e8400-e29b-41d4-a716-446655440001",
"file_name": "book.epub",
"file_hash": "abc123..."
}
responses:
'201':
description: Created
"/api/devices/{id}/file-aliases/{aliasId}":
delete:
tags: [book-matching]
summary: "Delete Device File Alias"
security:
- bearerAuth: []
responses:
'204':
description: No Content
put:
tags: [book-matching]
summary: "Update Device File Alias"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"file_name": "updated-book.epub",
"file_hash": "newhash123..."
}
responses:
'200':
description: OK
"/api/devices/{id}/regenerate-token":
put:
tags: [devices]
summary: "Regenerate Device Token"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/devices/{id}/shelves":
delete:
tags: [devices]
summary: "Remove from Shelf"
security:
- bearerAuth: []
responses:
'200':
description: OK
get:
tags: [devices]
summary: "Get Shelf"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [devices]
summary: "Add to Shelf"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"media_item_ids": ["550e8400-e29b-41d4-a716-446655440001"],
"shelf_name": "Default",
"shelf_position": 0
}
responses:
'200':
description: OK
"/api/devices/{id}/shelves/clear":
delete:
tags: [devices]
summary: "Clear Shelf"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/{id}/sidecar":
get:
tags: [devices]
summary: "Get Device Sidecar Config"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/devices/{id}/sidecar/download":
get:
tags: [devices]
summary: "Download Sidecar Config"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/jobs":
post:
tags: [jobs]
summary: "Create Job"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"type": "import",
"params": { "library_id": "990e8400-e29b-41d4-a716-446655440000" }
}
responses:
'202':
description: Accepted
"/api/jobs/{jobId}":
get:
tags: [jobs]
summary: "Get Job Status"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/libraries":
get:
tags: [libraries]
summary: "List Libraries (Admin)"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [libraries]
summary: "Create Library"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "Comics Collection",
"description": "Digital comics",
"type": "comics"
}
responses:
'201':
description: Created
"/api/libraries/browse":
get:
tags: [libraries]
summary: "Browse Library Folders"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/libraries/scan-settings":
get:
tags: [libraries]
summary: "Get Scan Settings"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [libraries]
summary: "Update Scan Settings"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"scan_poll_interval_seconds": 3600,
"auto_scan_enabled": true
}
responses:
'200':
description: Success
"/api/libraries/types":
get:
tags: [libraries]
summary: "Get Library Types"
security: []
responses:
'200':
description: OK
"/api/libraries/visibility":
get:
tags: [libraries]
summary: "Get Visible Libraries"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [libraries]
summary: "Set Library Visibility"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "library-uuid",
"is_visible": true
}
responses:
'200':
description: OK
"/api/libraries/{id}":
delete:
tags: [libraries]
summary: "Delete Library"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [libraries]
summary: "Get Library Details:\u003c|end|\u003e\u003c|start|\u003e assistant to=edit\u003c|channel|\u003eanalysis \u003c|constrain|\u003exml\u003c|message|\u003e\u003crfl:parameter name=\"path\"\u003e"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [libraries]
summary: "Update Library"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "My Updated Library",
"description": "Updated description"
}
responses:
'200':
description: OK
"/api/libraries/{id}/folders":
delete:
tags: [libraries]
summary: "Delete Library Folder"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"folder_path": "/path/to/library/folder"
}
responses:
'204':
description: No Content
get:
tags: [libraries]
summary: "Get Library Folders"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [libraries]
summary: "Add Library Folder"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"folder_path": "/path/to/comics"
}
responses:
'201':
description: Created
"/api/libraries/{id}/issues/list":
get:
tags: [libraries]
summary: "List Processing Issues"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/libraries/{id}/issues/stats":
get:
tags: [libraries]
summary: "Get Processing Issue Stats"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/libraries/{id}/issues/{issueId}":
delete:
tags: [libraries]
summary: "Delete Processing Issue"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/libraries/{id}/issues/{issueId}/{mediaItemId}/resolve":
post:
tags: [libraries]
summary: "Resolve Processing Issue"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/libraries/{id}/media-items":
get:
tags: [libraries]
summary: "Get Library Media Items"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/libraries/{id}/scan":
post:
tags: [libraries]
summary: "Scan Library"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/libraries/{id}/stats":
get:
tags: [libraries]
summary: "Get Library Statistics"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items":
get:
tags: [media-items]
summary: "List Media Items"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Create Media Item"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Example Book Title",
"author": "Jane Doe",
"isbn": "978-0-123456-78-9",
"description": "A great book about technology",
"file_path": "/library/books/example.epub",
"file_size": 1048576,
"mime_type": "application/epub+zip",
"series": "Tech Series",
"series_number": 1,
"tags": ["science-fiction", "technology", "ACME CORP."],
"publisher": "O'Reilly Media",
"contributors": ["John Smith", "ACME CORP."]
}
responses:
'201':
description: Created
"/api/media-items/bulk-delete":
post:
tags: [media-items]
summary: "Bulk Delete Media Items"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"media_item_ids": [
"550e8400-e29b-41d4-a716-446655440001",
"660e8400-e29b-41d4-a716-446655440002",
"770e8400-e29b-41d4-a716-446655440003"
]
}
responses:
'200':
description: OK
"/api/media-items/bulk-update":
post:
tags: [media-items]
summary: "Bulk Update Media Items"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"media_item_updates": [
{
"media_item_id": "550e8400-e29b-41d4-a716-446655440001",
"updates": {
"title": "Updated Title",
"genre": "Science Fiction",
"tags": ["science fiction", "space opera", "ACME CORP."]
}
},
{
"media_item_id": "660e8400-e29b-41d4-a716-446655440002",
"updates": {
"author": "Updated Author Name",
"language": "en"
}
}
]
}
responses:
'200':
description: OK
"/api/media-items/facets":
get:
tags: [media-items]
summary: "Get Media Item Facets"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/filter-count":
get:
tags: [media-items]
summary: "Filter Count"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/purge-archived":
post:
tags: [media-items]
summary: "Purge Archived Media Items"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/media-items/search":
get:
tags: [media-items]
summary: "Search Media Items (Unified):\u003c|end|\u003e\u003c|start|\u003eedit to=assistant\u003c|channel|\u003eanalysis\u003c|message|\u003eEdited docs/developer/api/media-items/create_media_item.md (1 replacement)\u003c|end|\u003e\u003c|start|\u003eedit to=assistant\u003c|channel|\u003eanalysis\u003c|message|\u003eEdited docs/developer/api/media-items/update_media_item.md (1 replacement)\u003c|end|\u003e\u003c|start|\u003eedit to=assistant\u003c|channel|\u003eanalysis\u003c|channel|\u003eEdited docs/developer/api/media-items/delete_media_item.md (1 replacement)\u003c|end|\u003e\u003c|start|\u003eedit to=assistant\u003c|channel|\u003eanalysis\u003c|message|\u003eEdited docs/developer/api/media-items/search_media_items.md (1 replacement)"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/{id}":
delete:
tags: [media-items]
summary: "Delete Media Item"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [media-items]
summary: "Get Media Item"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [media-items]
summary: "Update Media Item"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"title": "Updated Title",
"author": "Updated Author",
"description": "Updated description",
"series": "Series",
"series_number": 2
}
responses:
'200':
description: OK
"/api/media-items/{id}/annotations/deleted":
get:
tags: [media-items]
summary: "Deleted Annotations History"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/{id}/annotations/{annotationId}":
delete:
tags: [media-items]
summary: "Purge Deleted Annotation"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/media-items/{id}/annotations/{annotationId}/restore":
post:
tags: [media-items]
summary: "Restore Deleted Annotation"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/media-items/{id}/audio-speed":
put:
tags: [media-items]
summary: "Set Audio Speed"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"speed": 1.5
}
responses:
'200':
description: Success
"/api/media-items/{id}/audio/{trackIndex}":
get:
tags: [media-items]
summary: "Get Audio Track"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/{id}/bookmarks":
get:
tags: [media-items]
summary: "Get Media Bookmarks"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Create Media Bookmark"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"title": "Chapter 3",
"position": "kindle:pos:1:2",
"notes": "revisit this",
"cfi_position": "epubcfi(/6/4)",
"page_number": 42,
"chapter_number": 3,
"percentage": 35.5,
"chapter_reference": 3,
"origin": "android"
}
responses:
'200':
description: Success
"/api/media-items/{id}/bookmarks/{bookmarkId}":
delete:
tags: [media-items]
summary: "Delete Media Bookmark"
security:
- bearerAuth: []
responses:
'204':
description: No Content
put:
tags: [media-items]
summary: "Update Media Bookmark"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"title": "Chapter 3 (renamed)",
"notes": "updated note",
"position": "kindle:pos:1:2"
}
responses:
'200':
description: Success
"/api/media-items/{id}/chapters":
get:
tags: [media-items]
summary: "Get Audio Chapters"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/{id}/download":
get:
tags: [media-items]
summary: "Download Media Item File"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/media-items/{id}/highlights":
get:
tags: [media-items]
summary: "Get Highlights"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Create Highlight"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"selection_text": "Highlighted text...",
"start_position": "epubcfi(/6/4/2:15)",
"end_position": "epubcfi(/6/4/2:20)",
"color": "#ffff00",
"percentage_start": 0.45,
"percentage_end": 0.47
}
responses:
'201':
description: Created
"/api/media-items/{id}/highlights/{highlightId}":
delete:
tags: [media-items]
summary: "Delete Highlight"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [media-items]
summary: "Get Media Highlight"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [media-items]
summary: "Update Highlight"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"selection_text": "Updated text",
"color": "#00ff00"
}
responses:
'200':
description: OK
"/api/media-items/{id}/merge":
post:
tags: [media-items]
summary: "Merge Archived Media Item"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"target_id": "550e8400-e29b-41d4-a716-446655440000"
}
responses:
'200':
description: Success
"/api/media-items/{id}/notes":
get:
tags: [media-items]
summary: "Get Notes"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Create Note"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"content": "This is a note",
"position": "epubcfi(/6/4/2:15)",
"origin": "web"
}
responses:
'201':
description: Created
"/api/media-items/{id}/notes/{noteId}":
delete:
tags: [media-items]
summary: "Delete Note"
security:
- bearerAuth: []
responses:
'204':
description: No Content
get:
tags: [media-items]
summary: "Get Media Note"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [media-items]
summary: "Update Note"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"content": "Updated note content",
"position": "epubcfi(/6/4/2:20)"
}
responses:
'200':
description: OK
"/api/media-items/{id}/progress":
delete:
tags: [media-items]
summary: "Delete Media Item Progress"
security:
- bearerAuth: []
responses:
'200':
description: OK
get:
tags: [media-items]
summary: "Get Media Item Progress"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [media-items]
summary: "Update Media Item Progress"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"percentage": 0.0415,
"context_text": "was at war with one of these Powers it was generally at peace with the other. But what was strange w",
"epubcfi": "epubcfi(/6/4!/4/8[_idContainer003]/62/1:456)"
}
responses:
'200':
description: OK
"/api/media-items/{id}/rating":
delete:
tags: [media-items]
summary: "Delete Rating"
security:
- bearerAuth: []
responses:
'200':
description: OK
get:
tags: [media-items]
summary: "Get Rating"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Create Rating"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"rating": 8
}
responses:
'201':
description: Created
put:
tags: [media-items]
summary: "Update Rating"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"rating": 8,
"review": "Great book! Very enjoyable read."
}
responses:
'200':
description: OK
"/api/media-items/{id}/rescan":
post:
tags: [media-items]
summary: "Rescan Media Item"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/media-items/{id}/review":
delete:
tags: [media-items]
summary: "Delete Media Review"
security:
- bearerAuth: []
responses:
'200':
description: Success
get:
tags: [media-items]
summary: "Get Media Review"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [media-items]
summary: "Upsert Media Review"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"review": "A slow start, but the second act earns it."
}
responses:
'200':
description: Success
"/api/media-items/{id}/unarchive":
post:
tags: [media-items]
summary: "Unarchive Media Item"
security:
- bearerAuth: []
responses:
'204':
description: No Content
"/api/progress/{id}/history":
get:
tags: [progress]
summary: "Get Progress History"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/queue/devices/{device_id}/clear":
delete:
tags: [queue]
summary: "Clear Device Queue"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/queue/devices/{device_id}/items":
get:
tags: [queue]
summary: "List Device Queue Items"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/queue/devices/{device_id}/stats":
get:
tags: [queue]
summary: "Get Device Queue Statistics"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/queue/items":
get:
tags: [queue]
summary: "List All Queue Items (Admin)"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/queue/items/{item_id}":
delete:
tags: [queue]
summary: "Delete Queue Item"
security:
- bearerAuth: []
responses:
'204':
description: No Content
"/api/queue/items/{item_id}/retry":
post:
tags: [queue]
summary: "Retry Queue Item"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/saved-filters":
get:
tags: [saved-filters]
summary: "List Saved Filters"
security:
- bearerAuth: []
responses:
'200':
description: OK
post:
tags: [saved-filters]
summary: "Create Saved Filter"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "My Filter",
"resource_type": "media-items",
"filters": {}
}
responses:
'200':
description: Success
"/api/saved-filters/{id}":
delete:
tags: [saved-filters]
summary: "Delete Saved Filter"
security:
- bearerAuth: []
responses:
'200':
description: Success
get:
tags: [saved-filters]
summary: "Get Saved Filter"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [saved-filters]
summary: "Update Saved Filter"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"name": "Renamed Filter",
"resource_type": "media-items",
"filters": {}
}
responses:
'200':
description: Success
"/api/scanner/active":
get:
tags: [scanner]
summary: "Get Active Scans"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/scanner/active-summary":
get:
tags: [scanner]
summary: "Get Scan Summary"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/scanner/cancel/{jobId}":
post:
tags: [scanner]
summary: "Cancel Scan"
security:
- bearerAuth: []
responses:
'200':
description: Success
"/api/scanner/scan":
post:
tags: [scanner]
summary: "Scan Library"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000",
"force": false
}
responses:
'202':
description: Accepted
"/api/scanner/start":
post:
tags: [scanner]
summary: "Start Scanner"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"folder_paths": ["/data/books"]
}
responses:
'200':
description: OK
"/api/scanner/status/{jobId}":
get:
tags: [scanner]
summary: "Get Scan Status"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/scanner/stop":
post:
tags: [scanner]
summary: "Stop Scanner"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/scanner/watch/start":
post:
tags: [scanner]
summary: "Start Watch Mode"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000"
}
responses:
'200':
description: OK
"/api/scanner/watch/status":
get:
tags: [scanner]
summary: "Get Watch Mode Status"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/scanner/watch/stop":
post:
tags: [scanner]
summary: "Stop Watch Mode"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"library_id": "550e8400-e29b-41d4-a716-446655440000"
}
responses:
'200':
description: OK
"/api/series":
get:
tags: [series]
summary: "List Series"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/series/books":
get:
tags: [series]
summary: "Get Series Books"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/stats/books/{id}":
get:
tags: [stats]
summary: "Get Book Stats"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/stats/library-usage":
get:
tags: [stats]
summary: "Get Library Usage Statistics"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/stats/summary":
get:
tags: [stats]
summary: "Get Reading Summary"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/stats/this-week":
get:
tags: [stats]
summary: "Get This Week's Stats"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/sync/auto-link-books":
post:
tags: [book-matching]
summary: "Auto Link Books"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"confidence_threshold": 0.8,
"limit": 100
}
responses:
'200':
description: OK
"/api/sync/books/query":
post:
tags: [book-matching]
summary: "Search Books for Matching"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"identifiers": ["isbn:978-0345391802", "uuid:abc-123"],
"sha256": "a1b2c3d4e5f6abc123...",
"title": "The Hobbit",
"author": "J.R.R. Tolkien",
"file_size": 2456789
}
responses:
'200':
description: OK
"/api/sync/bulk-link-books":
post:
tags: [book-matching]
summary: "Bulk Link Books"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"links": [
{
"unlinked_book_id": "770e8400-e29b-41d4-a716-446655440002",
"media_item_id": "660e8400-e29b-41d4-a716-446655440001",
"confidence_score": 0.95
},
{
"unlinked_book_id": "880e8400-e29b-41d4-a716-446655440003",
"media_item_id": "990e8400-e29b-41d4-a716-446655440004",
"confidence_score": 0.87
}
]
}
responses:
'200':
description: OK
"/api/sync/kobo/{token}/bookmark":
post:
tags: [kobo]
summary: "Bookmark Sync"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"bookmarks": [
{
"BookmarkID": "bookmark123",
"ContentID": "book-uuid",
"StartPosition": 1234,
"Text": "Chapter 5",
"DateCreated": "2026-02-08T10:00:00Z"
}
]
}
responses:
'200':
description: OK
"/api/sync/kobo/{token}/markup":
post:
tags: [kobo]
summary: "Markup Sync"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"bookmarks": [
{
"BookmarkID": "bookmark123",
"ContentID": "book-uuid",
"StartPosition": 1234,
"EndPosition": 1456,
"Text": "Highlighted text from book",
"Annotation": "My annotation",
"DateCreated": "2026-02-08T10:00:00Z",
"Chapter": "Chapter 1",
"Hidden": false
}
]
}
responses:
'200':
description: OK
"/api/sync/kobo/{token}/sync-from-server":
post:
tags: [kobo]
summary: "Sync From Server"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"book_ids": ["content-id-1", "content-id-2"],
"full_sync": false
}
responses:
'200':
description: OK
"/api/sync/kobo/{token}/v1/analytics/gettests":
post:
tags: [kobo]
summary: "Analytics GetTests"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"data": {}
}
responses:
'200':
description: OK
"/api/sync/kobo/{token}/v1/initialization":
get:
tags: [kobo]
summary: "Kobo Initialization"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/api/sync/koreader/bookmarks":
post:
tags: [koreader]
summary: "Sync Bookmarks"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"book_sha256": "64-hex-char-sha256",
"bookmarks": [
{
"chapter": 3,
"datetime": "2026-08-20T10:00:00Z",
"pos0": "/body/Doc[4]/Sec[2]",
"page": 25,
"text": "",
"type": "bookmark",
"percentage": 0.125
}
],
"highlights": [
{
"datetime": "2026-08-20T10:05:00Z",
"pos0": "/body/Doc[4]/Sec[2]/text()[3]:0",
"pos1": "/body/Doc[4]/Sec[2]/text()[3]:42",
"text": "Text to remember",
"notes": "Why this matters",
"type": "highlight",
"color": "blue",
"dedup_key": "echo-key-from-server"
}
]
}
responses:
'200':
description: OK
"/api/sync/koreader/library":
get:
tags: [koreader]
summary: "Get Library"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/api/sync/koreader/metadata/{uuid}":
get:
tags: [koreader]
summary: "Get Metadata"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/api/sync/koreader/progress":
post:
tags: [koreader]
summary: "Sync Progress"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"books": [
{
"uuid": "774641f9-317b-4087-8e04-53bb4392ae56",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"title": "1984",
"authors": ["George Orwell"],
"percentage": 0.045,
"context_text": "from day to day, but there was none in which Goldstein was not the principal figure. He was the prim",
"page": 14,
"total_pages": 311,
"epubcfi": "/body/DocFragment[1]/body/p[29]/text().598",
"device_info": {
"koreader_version": "v2026.07.1",
"device_model": "emulator"
}
}
],
"sync_mode": "immediate"
}
responses:
'202':
description: Accepted
"/api/sync/koreader/rating":
get:
tags: [koreader]
summary: "Get KOReader Rating"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
post:
tags: [koreader]
summary: "Set KOReader Rating"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"rating": 8
}
responses:
'200':
description: Success
"/api/sync/koreader/resolve":
get:
tags: [koreader]
summary: "Resolve Book:\u003c|end|\u003e\u003c|start|\u003e assistant to=edit\u003c|channel|\u003eanalysis \u003c|constrain|\u003exml\u003c|message|\u003e\u003crfl:parameter name=\"path\"\u003e"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/api/sync/koreader/review":
get:
tags: [koreader]
summary: "Get KOReader Review"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
post:
tags: [koreader]
summary: "Set KOReader Review"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"review": "A slow start, but the second act earns it."
}
responses:
'200':
description: Success
"/api/sync/koreader/stats":
post:
tags: [koreader]
summary: "Push KOReader Stats"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
requestBody:
content:
application/json:
example: |-
{
"total_seconds": 3600
}
responses:
'200':
description: Success
"/api/sync/unlinked-books/{id}/suggestions":
get:
tags: [book-matching]
summary: "Get Unlinked Book Suggestions"
security:
- bearerAuth: []
responses:
'200':
description: OK
"/api/system/config":
get:
tags: [system]
summary: "Get System Configuration"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [system]
summary: "Update System Configuration"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"base_url": "https://books.example.com",
"default_timezone": "UTC"
}
responses:
'200':
description: Success
"/api/system/settings":
get:
tags: [system]
summary: "Get System Settings"
security:
- bearerAuth: []
responses:
'200':
description: OK
put:
tags: [system]
summary: "Update System Setting"
security:
- bearerAuth: []
requestBody:
content:
application/json:
example: |-
{
"key": "scan_poll_interval_seconds",
"value": "60"
}
responses:
'200':
description: Success
"/opds/devices/{deviceId}/catalog":
get:
tags: [opds]
summary: "OPDS Feeds"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/opds/devices/{deviceId}/cover/{bookId}":
get:
tags: [opds]
summary: "OPDS Publication"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK
"/opds/devices/{deviceId}/download/{bookId}":
get:
tags: [opds]
summary: "OPDS Acquisition"
description: 'Device token: Bearer header (KOReader) or ?token= query (Kobo/OPDS).'
responses:
'200':
description: OK