# Sync Bookmarks Sync bookmarks, notes, and highlights from a KOReader device (bidirectional — the response also returns the server's current state for the book so the device can reconcile). **Endpoint**: `POST /api/sync/koreader/bookmarks` **Auth**: Device token (Bearer) ## Request Body | Field | Type | Required | Description | | ------------ | ------ | --------------------- | ----------------------------------------------------------------- | | book_uuid | string | one of uuid/sha | Book UUID (highest-confidence match) | | book_sha256 | string | one of uuid/sha | Full-file SHA-256 (64 hex chars); format-aware (also matches `media_item_formats`, so a KEPUB/PDF download matches) | | bookmarks | array | No | Bookmark objects | | notes | array | No | Note objects | | highlights | array | No | Highlight objects | At least one of `book_uuid` or `book_sha256` is required; `book_sha256` resolves through the shared BookResolver. ### Bookmark / Note / Highlight Object All three types share the same KOReader annotation shape: | Field | Type | Required | Description | | ------------ | ------- | -------- | ---------------------------------------------------- | | chapter | int | No | Chapter index | | datetime | string | No | ISO 8601 creation/edit timestamp | | pos0 / pos1 | string | No | Start/end xpointer (or `page:N` / bare page) | | page | int | No | Page number (fallback location when `pos0` is empty) | | text | string | No | Highlighted text | | notes | string | No | Note text attached to the annotation | | type | string | No | Annotation type (`highlight`, `note`, `bookmark`) | | color | string | No | Highlight color (highlights only) — KOReader palette name, see below | | percentage | float | No | Position within the book (0-1) | | book_sha256 | string | No | Per-annotation SHA-256; overrides the request-level book match | | dedup_key | string | No | Stable echo key; an entry whose content is unchanged from what the server previously served is recognized as an echo rather than a new edit | ### Color Semantics KOReader paints highlights from a fixed palette of color names; the web reader uses hex swatches. Colors are mapped at the boundary (unmappable values fall back to yellow on both sides): | KOReader name | Web hex | | ------------- | --------- | | yellow, orange | `#ffd54f` | | green, olive | `#a5d6a7` | | cyan, blue | `#90caf9` | | purple | `#ce93d8` | | red | `#f48fb1` | - An echo (device re-reporting an annotation it received from the server) carries **no color**, so the stored web color is never clobbered. - A non-empty color means the user edited the highlight on the device; it is mapped to the nearest web swatch. ### Example Request ```json { "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" } ] } ``` ## Response (200 OK) ```json { "sync_status": "ok", "bookmarks_synced": 1, "notes_synced": 0, "highlights_synced": 1 } ``` ## Error Responses | Code | Description | | ---- | -------------------------------------------------- | | 400 | Invalid request, or neither uuid nor SHA provided | | 401 | Missing/invalid device token | | 404 | Book not found by SHA-256 |