Files
bookhoard/docs/developer/api/progress/update_media_progress.md
T
John O'Keefe b10bf3e8c7 docs(api): real progress endpoint contract; remove nonexistent-endpoint docs
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.
2026-09-26 21:27:44 -04:00

92 lines
3.5 KiB
Markdown

# Update Media Item Progress
Submit reading progress for a media item. This is the position-authority
ingest point: the server independently verifies the submission against
the book and heals it when the client's projection is wrong.
**Endpoint**: `PUT /api/media-items/:id/progress`
**Auth**: Required (Bearer token)
**Content-Type**: `application/json`
See the [Position Contract](position-contract.md) for the three-tier
submission model, the verification/healing semantics, and the offset
currencies.
## Path Parameters
| Parameter | Type | Required | Description |
| --------- | ------------- | -------- | ---------------- |
| id | string (UUID) | Yes | Media item UUID |
## Request Body
All fields are optional; submit what your renderer can observe.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `percentage` | float | Position as a fraction of the whole book (0..1). Tier 1 — the universal field. |
| `context_text` | string | Up to 100 whitespace-normalized chars starting at the anchor. Tier 2 — enables verification and healing. |
| `epubcfi` | string | Standard wrapped CFI (UTF-16 terminals). Tier 3 — the structural anchor. Note: the server re-derives the stored canonical CFI; a client's own spine numbering is healed if it disagrees with the OPF spine. |
| `character_offset` | int | Book-wide rune offset. Accepted but recomputed server-side from the verified anchor on every verified save. |
| `current_page`, `total_pages` | int | Fixed-layout position. For fixed-layout formats the page index is the canonical locator. |
| `chapter`, `chapter_progress` | int, float | Chapter index and within-chapter fraction. |
| `reading_mode` | string | `paged` or `scrolled` (fixed-layout reader state). |
| `zoom_level`, `scroll_position_x`, `scroll_position_y` | float | Fixed-layout viewport state. |
### Example Request (reflowable, all three tiers)
```http
PUT /api/media-items/774641f9-317b-4087-8e04-53bb4392ae56/progress
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
```
```json
{
"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)"
}
```
### Example Request (fixed-layout)
```json
{
"percentage": 0.15,
"current_page": 30,
"total_pages": 194,
"reading_mode": "paged"
}
```
## Behavior
- The submission is verified against the book's XHTML when
`context_text` is present and the book is convertible reflowable: the
CFI is resolved, the text at the anchor is compared with
`context_text`, and mismatches heal by text search (percentage
disambiguates repeats). See [Position Contract](position-contract.md).
- **Anti-clobber guard**: a submission with `percentage < 0.005` is
ignored with `{"status": "ignored"}` when the stored row already holds
a percentage above `0.01` — re-opening a book at its first page does
not wipe real progress.
- The response is the stored row after verification, including the
healed `epubcfi` and the refreshed `character_offset` when
verification ran.
## Response (200 OK)
The saved progress row (same shape as
[GET](get_media_progress.md), minus the GET-time handles). The
`epubcfi` and `percentage` in the response are the server-verified
values, which may differ from the submitted ones when healing occurred.
## Error Responses
| Code | Description |
| ---- | ----------- |
| 400 | Invalid request data |
| 401 | Invalid or expired token |
| 500 | Database error |