The progress documentation described GET/POST /api/progress/:id — endpoints that do not exist in the router — while the endpoint every client actually uses (GET/PUT/DELETE /api/media-items/:id/progress) had no field-level docs at all. New: - progress/position-contract.md: the canonical position model — server as position authority, the three-tier submission (percentage / context_text / epubcfi), ingest verification and healing, the restore handles, the OPF spine numbering hazard (canonical CFI spine steps include linear="no" items; clients resolve documents by anchor_href and land by css_selector + char_offset, never by spine step), the offset currencies (UTF-16 at the wire, runes internal), and context_text rules. - progress/get_media_progress.md and update_media_progress.md: the real endpoints with full field tables, conditionality of the restore handles, the first-page anti-clobber guard, and healed-response semantics. - progress/delete_media_progress.md: the real DELETE route. - koreader/sync_progress.md and koreader/get_metadata.md rewritten to the actual payloads: the plugin sends a single-book array whose "epubcfi" field is a CRE xpointer; the metadata response navigates via koreader_xpointer (canonical CFI converted back to CRE), with page as the canonical locator for fixed-layout books. Removed: the five files documenting the nonexistent /api/progress/:id GET/POST/DELETE endpoints. Kept get_progress_history.md (that route exists). The legacy developer/api-reference.md and the indexed api/api-reference.md progress sections now match the wire and link the new docs; the duplicate "Universal Progress" section points at Reading Progress.
3.8 KiB
3.8 KiB
Get Media Item Progress
Get the stored reading progress for a media item, plus the server-derived restore handles for reflowable books.
Endpoint: GET /api/media-items/:id/progress
Auth: Required (Bearer token)
See Position Contract for the semantics of every field — what is verified, what the currencies are, and how clients should restore.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string (UUID) | Yes | Media item UUID |
Example Request
GET /api/media-items/774641f9-317b-4087-8e04-53bb4392ae56/progress
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response (200 OK) — no progress stored
When the item has no progress row, an empty fixed-layout-style stub is returned (not 404):
{
"current_page": 0,
"total_pages": null
}
Response (200 OK) — progress stored
{
"id": "e8239659-0ed6-42ae-a946-8440d7655b42",
"media_item_id": "774641f9-317b-4087-8e04-53bb4392ae56",
"user_id": "1b64992e-3408-4d84-9e03-e2dc4950e1dd",
"current_page": null,
"total_pages": null,
"last_read_at": "2026-09-26T14:52:34.806446Z",
"percentage": 0.045,
"character_offset": 16375,
"epubcfi": "epubcfi(/6/4!/4/8[_idContainer003]/58/1:598)",
"chapter": null,
"chapter_progress": null,
"format_group": "reflowable",
"total_characters": 592216,
"chapter_count": 1,
"last_sync_device": "web",
"last_sync_source": "koreader",
"last_sync_timestamp": "2026-09-26T14:52:34.806446Z",
"css_selector": "body>div:nth-child(4)>p:nth-child(29)",
"anchor_href": "1984.xhtml",
"char_offset": 598,
"context_text": "from day to day, but there was none in which Goldstein was not the principal figure. He was the prim"
}
Field Reference
Base fields (always present when a row exists):
| Field | Type | Description |
|---|---|---|
percentage |
float | Position as a fraction of the whole book (0..1). |
epubcfi |
string | The stored canonical standard CFI. Spine steps index the OPF spine as written, including linear="no" items — do not resolve them against a readium reading order. See the Position Contract. |
context_text |
string | The stored verification context (≤100 whitespace-normalized chars from the anchor). |
character_offset |
int | Book-wide rune offset. Internal currency — consistent with total_characters. |
current_page, total_pages |
int | Fixed-layout page position (null for reflowable). |
chapter, chapter_progress |
int, float | Chapter index and within-chapter fraction, when known. |
format_group |
string | reflowable, fixed_layout, comic_archive, … Gates the restore handles. |
total_characters, chapter_count |
int | Book metrics, for client-side fraction math. |
last_sync_device, last_sync_source, last_sync_timestamp |
— | Which client last wrote the row. |
Restore handles (conditional — served only for convertible reflowable books whose stored anchor re-resolves at GET time):
| Field | Type | Description |
|---|---|---|
anchor_href |
string | The spine document containing the anchor (e.g. 1984.xhtml). Resolve your resource by this, never by the CFI's spine step. |
css_selector |
string | Body-relative chain to the anchor's block element. |
char_offset |
int | Anchor offset within the block's concatenated text, in UTF-16 code units. |
epubcfi |
string | Re-served (possibly healed) canonical CFI — present whenever re-verification produced one. |
Error Responses
| Code | Description |
|---|---|
| 400 | Invalid media item id |
| 401 | Invalid or expired token |
| 500 | Database error |