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.
2422 lines
61 KiB
YAML
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
|