fix(bruno): convert drifted body keys to body.data — CLI scenario runs now carry bodies

Follow-up to the sweep route audit, correcting its diagnosis: the CLI
DOES read .yml bodies — via OpenCollection's `body.data` string form
(the NewDevDBSetup script always worked because it used it). The
failing scenario POSTs used `body.json` (structured) / `body.jsonBody`
(string) — keys the CLI silently ignores, sending Content-Length: 0
with form-urlencoded content-type, so every server bind failed.

- 81 bodies converted to data-form (json maps serialized; jsonBody
  strings kept verbatim, {{vars}} intact).
- 6 pre-existing TRUNCATED payloads repaired: the original generator
  cut bodies at the first {{var}} (every SHA-256-identified scenario
  plus Sync Progress/Sync Bookmarks shipped mid-JSON and 400'd from
  day one). Rewritten whole, faithful to each file's documented
  purpose; book_sha256/book_uuid added to the environment.
- environments: opds_base_url correction from the sweep retained.

Verified live against the rebuilt dev container: the full koreader
scenario tree runs green through `bru run` — 14/14 (202s across
immediate/checkpoint/SHA-256 progress, 200s bookmarks, highlights,
notes; SHA-256 book identification exercised against a real
file_sha256).
This commit is contained in:
John O'Keefe committed 2026-10-17 12:22:35 -04:00
1 parent 63a20dcc95
commit 09b6693505
83 files changed
+386 -2769

No files matched your search

+6 -85
View File
@@ -2,95 +2,16 @@ info:
name: Get Analytics Tests
type: http
seq: 7
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/analytics/gettests'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
platform: android
firmware_version: 4.30.19023
docs: |-
## Get Kobo Analytics Tests
Retrieves A/B testing configuration and feature flags for Kobo device.
**Method:** POST
**Endpoint:** /api/sync/kobo/v1/analytics/gettests
**Authentication:** Bearer token
**Request Body:**
- `platform` (string): Device platform
- `android`: Kobo Android app
- `kobo`: Native Kobo firmware
- `firmware_version` (string): Firmware version (e.g., "4.30.19023")
- `device_model` (string, optional): Device model identifier
- `locale` (string, optional): Device locale (e.g., "en_US")
**Response:**
- `tests` (array): Active A/B tests
- `test_name` (string): Test identifier
- `variant` (string): Assigned variant (A, B, C, etc.)
- `enabled` (boolean): Whether test is active
- `parameters` (object): Test-specific parameters
- `features` (object): Feature flags
- `feature_name` (boolean/string): Feature state
- `configuration` (object): Device configuration
- `sync_interval_minutes` (integer): Recommended sync frequency
- `batch_size` (integer): Max items per batch sync
- `timeout_seconds` (integer): Request timeout
- `version` (string): Configuration version
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 400: Invalid request parameters
**Analytics Testing Purpose:**
- Kobo uses A/B testing for UX features
- Feature flags for gradual rollout
- Performance monitoring configuration
- Sync behavior optimization
- Device-specific tuning
**Common Tests:**
- Sync frequency optimization
- UI/UX variations
- Network usage patterns
- Battery life improvements
- Feature set variations by model
**Feature Flags:**
- New sync features
- Beta functionality
- Platform-specific capabilities
- Experimental features
**Configuration Parameters:**
- Optimal sync intervals for device
- Batch size limits based on device capabilities
- Timeout values for network conditions
- Retry logic configuration
- Cache policy settings
**Usage:**
- Called during device initialization
- Refreshed daily or weekly
- Cached on device
- Affects sync behavior
- Can be overridden by server
**Use Cases:**
- Device initialization
- Feature rollout testing
- Performance optimization
- UX experiment participation
- Configuration management
data: "{\n \"platform\": \"android\",\n \"firmware_version\": \"4.30.19023\"\n}"
docs: "## Get Kobo Analytics Tests\n\nRetrieves A/B testing configuration and feature flags for Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/v1/analytics/gettests\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `platform` (string): Device platform\n - `android`: Kobo Android app\n - `kobo`: Native Kobo firmware\n- `firmware_version` (string): Firmware version (e.g., \"4.30.19023\")\n- `device_model` (string, optional): Device model identifier\n- `locale` (string, optional): Device locale (e.g., \"en_US\")\n\n**Response:**\n- `tests` (array): Active A/B tests\n - `test_name` (string): Test identifier\n - `variant` (string): Assigned variant (A, B, C, etc.)\n - `enabled` (boolean): Whether test is active\n - `parameters` (object): Test-specific parameters\n- `features` (object): Feature flags\n - `feature_name` (boolean/string): Feature state\n- `configuration` (object): Device configuration\n - `sync_interval_minutes` (integer): Recommended sync frequency\n\
\ - `batch_size` (integer): Max items per batch sync\n - `timeout_seconds` (integer): Request timeout\n- `version` (string): Configuration version\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 400: Invalid request parameters\n\n**Analytics Testing Purpose:**\n- Kobo uses A/B testing for UX features\n- Feature flags for gradual rollout\n- Performance monitoring configuration\n- Sync behavior optimization\n- Device-specific tuning\n\n**Common Tests:**\n- Sync frequency optimization\n- UI/UX variations\n- Network usage patterns\n- Battery life improvements\n- Feature set variations by model\n\n**Feature Flags:**\n- New sync features\n- Beta functionality\n- Platform-specific capabilities\n- Experimental features\n\n**Configuration Parameters:**\n- Optimal sync intervals for device\n- Batch size limits based on device capabilities\n- Timeout values for network conditions\n- Retry logic configuration\n- Cache policy settings\n\n**Usage:**\n- Called during device initialization\n\
- Refreshed daily or weekly\n- Cached on device\n- Affects sync behavior\n- Can be overridden by server\n\n**Use Cases:**\n- Device initialization\n- Feature rollout testing\n- Performance optimization\n- UX experiment participation\n- Configuration management"
@@ -8,38 +8,10 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"confidence_threshold\": 0.8,\n \"limit\": 50"
data: "{\n \"confidence_threshold\": 0.8,\n \"limit\": 50"
headers:
- key: Content-Type
value: application/json
- key: Authorization
value: Bearer {{authToken
docs: |-
## Auto-Link Unlinked Books
Automatically links unlinked books to media items based on title and author matching with a configurable confidence threshold.
**Method:** POST
**Endpoint:** /sync/auto-link-books
**Authentication:** Bearer token
**Request Body:**
- `confidence_threshold` (number, optional): Minimum confidence score for auto-linking (0-1, default: 0.8)
- `limit` (number, optional): Maximum number of books to auto-link (default: 50)
**Response:**
- `results` (array): Results for each auto-link attempt
- `total` (number): Total number of books processed
- `success` (number): Number of successful links
- `failed` (number): Number of failed links
**Status Codes:**
- 200: Success
- 400: Invalid request data
- 401: Unauthorized
- 500: Internal server error
**Note:** Higher confidence thresholds produce fewer but more accurate matches. Consider the tradeoff between automation and accuracy.
docs: "## Auto-Link Unlinked Books\n\n Automatically links unlinked books to media items based on title and author matching with a configurable confidence threshold.\n\n **Method:** POST\n\n **Endpoint:** /sync/auto-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `confidence_threshold` (number, optional): Minimum confidence score for auto-linking (0-1, default: 0.8)\n - `limit` (number, optional): Maximum number of books to auto-link (default: 50)\n\n **Response:**\n - `results` (array): Results for each auto-link attempt\n - `total` (number): Total number of books processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Higher confidence thresholds produce fewer but more accurate matches. Consider the tradeoff between automation and accuracy."
@@ -8,40 +8,10 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"links\": [\n {\n \"unlinked_book_id\": \"{{unlinkedBookId1"
data: "{\n \"links\": [\n {\n \"unlinked_book_id\": \"{{unlinkedBookId1"
headers:
- key: Content-Type
value: application/json
- key: Authorization
value: Bearer {{authToken
docs: |-
## Bulk Link Unlinked Books
Links multiple unlinked books to media items in a single request.
**Method:** POST
**Endpoint:** /sync/bulk-link-books
**Authentication:** Bearer token
**Request Body:**
- `links` (array): Array of link objects
- `unlinked_book_id` (string): Unlinked book UUID
- `media_item_id` (string): Media item UUID to link to
- `confidence_score` (number): Match confidence (0-1)
**Response:**
- `results` (array): Results for each link attempt
- `total` (number): Total number of links processed
- `success` (number): Number of successful links
- `failed` (number): Number of failed links
**Status Codes:**
- 200: Success
- 400: Invalid request data
- 401: Unauthorized
- 500: Internal server error
**Note:** Use this endpoint after reviewing suggestions from the Get Unlinked Book Suggestions endpoint.
docs: "## Bulk Link Unlinked Books\n\n Links multiple unlinked books to media items in a single request.\n\n **Method:** POST\n\n **Endpoint:** /sync/bulk-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `links` (array): Array of link objects\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1)\n\n **Response:**\n - `results` (array): Results for each link attempt\n - `total` (number): Total number of links processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Use this endpoint after reviewing suggestions from the Get Unlinked Book Suggestions endpoint."
@@ -8,46 +8,9 @@ http:
auth: inherit
body:
type: json
jsonBody: "[\n {\n \"ContentId\": \"{{bookUUID"
data: "[\n {\n \"ContentId\": \"{{bookUUID"
headers:
- key: Authorization
value: Bearer {{koboToken
docs: |-
## Sync from Bookhoard to Kobo
Server-initiated sync pushing progress, bookmarks, and highlights from Bookhoard to Kobo device. Two-way sync endpoint.
**Method:** POST
**Endpoint:** /api/sync/kobo/sync-from-server
**Authentication:** Bearer token with Kobo device identification
**Headers:**
- `x-kobo-device` (string): JSON string containing Kobo device info
- `DeviceId`: Kobo device ID
- `Model`: Kobo device model
- `SerialNumber`: Kobo device serial number
**Request Body:** Array of sync data objects
- `ContentId` (string): Book UUID
- `PercentRead` (number): Reading progress percentage (0-100)
- `LastModified` (string): ISO 8601 timestamp
- `Bookmarks` (array, optional): Array of bookmark objects
- `BookmarkId`: Unique bookmark ID
- `ContentId`: Book UUID
- `BookmarkText`: Bookmark text/note
- `BookmarkType`: Type (bookmark, annotation, etc.)
- `BookmarkTitle`: Bookmark title
- `Highlights` (array, optional): Array of highlight objects (same structure as bookmarks)
**Response:**
- Sync result confirmation
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 500: Internal server error
**Note:** Allows Bookhoard server to push updates to Kobo device, including reading progress, bookmarks, and highlights.
docs: "## Sync from Bookhoard to Kobo\n\n Server-initiated sync pushing progress, bookmarks, and highlights from Bookhoard to Kobo device. Two-way sync endpoint.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/kobo/sync-from-server\n\n **Authentication:** Bearer token with Kobo device identification\n\n **Headers:**\n - `x-kobo-device` (string): JSON string containing Kobo device info\n - `DeviceId`: Kobo device ID\n - `Model`: Kobo device model\n - `SerialNumber`: Kobo device serial number\n\n **Request Body:** Array of sync data objects\n - `ContentId` (string): Book UUID\n - `PercentRead` (number): Reading progress percentage (0-100)\n - `LastModified` (string): ISO 8601 timestamp\n - `Bookmarks` (array, optional): Array of bookmark objects\n - `BookmarkId`: Unique bookmark ID\n - `ContentId`: Book UUID\n - `BookmarkText`: Bookmark text/note\n - `BookmarkType`: Type (bookmark, annotation, etc.)\n - `BookmarkTitle`: Bookmark title\n - `Highlights` (array,\
\ optional): Array of highlight objects (same structure as bookmarks)\n\n **Response:**\n - Sync result confirmation\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Allows Bookhoard server to push updates to Kobo device, including reading progress, bookmarks, and highlights."
@@ -2,105 +2,16 @@ info:
name: Sync Books from Server to Kobo
type: http
seq: 9
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/sync-from-server'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
force_sync: true
books:
- book-uuid-1
- book-uuid-2
docs: |-
## Sync Books from Server to Kobo
Pulls reading progress, annotations, and bookmarks from server to Kobo device.
**Method:** POST
**Endpoint:** /api/sync/kobo/sync-from-server
**Authentication:** Bearer token
**Request Body:**
- `force_sync` (boolean): Force full sync (ignore last sync time)
- `books` (array, optional): List of book UUIDs to sync
- If empty, syncs all books with server data
- If specified, only syncs listed books
- `sync_options` (object, optional):
- `since_date` (string): ISO 8601 timestamp for incremental sync
- `include_annotations` (boolean): Include highlights/notes
- `include_progress` (boolean): Include reading progress
- `conflict_resolution` (string): `most_recent`, `server_wins`, `client_wins`
**Response:**
- `synced` (integer): Number of books synced
- `skipped` (integer): Books with no server changes
- `failed` (integer): Books that failed to sync
- `results` (array): Per-book sync results
- `book_id` (string): Book UUID
- `status` (string): `synced`, `skipped`, `failed`
- `progress_pulled` (boolean): Whether progress was downloaded
- `annotations_pulled` (integer): Number of annotations downloaded
- `error` (string, optional): Error message if failed
- `server_timestamp` (string): Server timestamp of sync
**Status Codes:**
- 200: Sync completed
- 207: Multi-status (some succeeded, some failed)
- 401: Unauthorized
- 400: Invalid request
**Sync Direction:**
- **Server → Device** (this endpoint)
- Device → Server: Use `/sync/kobo/markup` endpoint
- Bidirectional sync achieved by calling both
**Pull Sync Use Cases:**
- New device setup (download all progress)
- Device replacement (restore from server)
- Multi-device sync (pull changes from other devices)
- Conflict resolution (server wins)
- Manual "Download from server" operation
**Conflict Resolution:**
- `most_recent`: Latest timestamp wins (default)
- `server_wins`: Server data always used
- `client_wins`: Device data preserved
- Applied per-book, per-item
**Sync Optimization:**
- Incremental sync by default (since last sync)
- Force sync does full comparison
- Book-level batching (10 books per batch)
- Delta transfer (only changed items)
- Compression for large annotation sets
**Kobo Device Behavior:**
- Device updates local database
- Progress reflected in reading view
- Annotations appear in Notebook
- Bookmarks updated in navigation
- Conflict warnings shown to user
- Sync progress displayed on screen
**Performance:**
- Small sync (1-10 books): 2-5 seconds
- Medium sync (10-50 books): 5-15 seconds
- Large sync (50-200 books): 15-45 seconds
- Timeout: 120 seconds
**Use Cases:**
- Initial device sync
- After firmware update
- From another device's changes
- Manual sync request
- Conflict recovery
- Data restoration
data: "{\n \"force_sync\": true,\n \"books\": [\n \"book-uuid-1\",\n \"book-uuid-2\"\n ]\n}"
docs: "## Sync Books from Server to Kobo\n\nPulls reading progress, annotations, and bookmarks from server to Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/sync-from-server\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `force_sync` (boolean): Force full sync (ignore last sync time)\n- `books` (array, optional): List of book UUIDs to sync\n - If empty, syncs all books with server data\n - If specified, only syncs listed books\n- `sync_options` (object, optional):\n - `since_date` (string): ISO 8601 timestamp for incremental sync\n - `include_annotations` (boolean): Include highlights/notes\n - `include_progress` (boolean): Include reading progress\n - `conflict_resolution` (string): `most_recent`, `server_wins`, `client_wins`\n\n**Response:**\n- `synced` (integer): Number of books synced\n- `skipped` (integer): Books with no server changes\n- `failed` (integer): Books that failed to sync\n- `results` (array): Per-book sync results\n - `book_id` (string):\
\ Book UUID\n - `status` (string): `synced`, `skipped`, `failed`\n - `progress_pulled` (boolean): Whether progress was downloaded\n - `annotations_pulled` (integer): Number of annotations downloaded\n - `error` (string, optional): Error message if failed\n- `server_timestamp` (string): Server timestamp of sync\n\n**Status Codes:**\n- 200: Sync completed\n- 207: Multi-status (some succeeded, some failed)\n- 401: Unauthorized\n- 400: Invalid request\n\n**Sync Direction:**\n- **Server → Device** (this endpoint)\n- Device → Server: Use `/sync/kobo/markup` endpoint\n- Bidirectional sync achieved by calling both\n\n**Pull Sync Use Cases:**\n- New device setup (download all progress)\n- Device replacement (restore from server)\n- Multi-device sync (pull changes from other devices)\n- Conflict resolution (server wins)\n- Manual \"Download from server\" operation\n\n**Conflict Resolution:**\n- `most_recent`: Latest timestamp wins (default)\n- `server_wins`: Server data always used\n- `client_wins`:\
\ Device data preserved\n- Applied per-book, per-item\n\n**Sync Optimization:**\n- Incremental sync by default (since last sync)\n- Force sync does full comparison\n- Book-level batching (10 books per batch)\n- Delta transfer (only changed items)\n- Compression for large annotation sets\n\n**Kobo Device Behavior:**\n- Device updates local database\n- Progress reflected in reading view\n- Annotations appear in Notebook\n- Bookmarks updated in navigation\n- Conflict warnings shown to user\n- Sync progress displayed on screen\n\n**Performance:**\n- Small sync (1-10 books): 2-5 seconds\n- Medium sync (10-50 books): 5-15 seconds\n- Large sync (50-200 books): 15-45 seconds\n- Timeout: 120 seconds\n\n**Use Cases:**\n- Initial device sync\n- After firmware update\n- From another device's changes\n- Manual sync request\n- Conflict recovery\n- Data restoration"
@@ -2,90 +2,17 @@ info:
name: Sync Multiple Books Progress
type: http
seq: 3
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
body:
type: json
json:
ReadingSync:
- ContentId: book-1-uuid
PercentRead: 25.0
EntitlementId: entitlement-1
RemainingTimeMinutes: 240
FirstReadTime: '2026-01-25T10:00:00Z'
LastModified: '2026-01-30T18:00:00Z'
- ContentId: book-2-uuid
PercentRead: 78.5
EntitlementId: entitlement-2
RemainingTimeMinutes: 45
FirstReadTime: '2026-01-25T14:00:00Z'
LastModified: '2026-01-30T20:00:00Z'
BookmarkSync: []
docs: |-
## Sync Multiple Books Progress
Synchronizes reading progress for multiple books in a single request.
**Method:** POST
**Endpoint:** /api/sync/kobo/markup
**Authentication:** Bearer token
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: Device information (Model: "Kobo Aura")
**Request Body:**
- `ReadingSync` (array): Multiple progress items
- Each item contains: ContentId, PercentRead, EntitlementId, etc.
- `BookmarkSync` (array): Empty for progress-only batch
**Response:**
- `total` (integer): Total items in request
- `synced` (integer): Successfully synced
- `failed` (integer): Failed items
- `results` (array): Per-item results
- `ContentId` (string): Book UUID
- `status` (string): `synced`, `failed`, `skipped`
- `error` (string, optional): Error message if failed
**Status Codes:**
- 200: Batch sync completed
- 207: Multi-status (some succeeded, some failed)
- 401: Unauthorized
- 413: Payload too large (>1MB)
**Batch Sync Advantages:**
- Efficient sync of entire library
- Reduces HTTP overhead
- Faster for devices with many books
- Atomic operation (all or nothing by default)
**Kobo Batch Sync Behavior:**
- Triggered when device connects after being offline
- Occurs during manual "Sync now" operation
- Limited to 100 books per request
- Progress updates shown on device
- Failed items retried individually
**Performance:**
- Typical batch: 10-50 books in 1-3 seconds
- Large batch: 50-100 books in 3-8 seconds
- Timeout: 30 seconds
- Rate limit: 10 batches per minute per device
**Use Cases:**
- Initial device sync after registration
- Catch-up sync after extended offline period
- Library-wide progress update
- Pre-sync before device firmware update
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-1-uuid\",\n \"PercentRead\": 25.0,\n \"EntitlementId\": \"entitlement-1\",\n \"RemainingTimeMinutes\": 240,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T18:00:00Z\"\n },\n {\n \"ContentId\": \"book-2-uuid\",\n \"PercentRead\": 78.5,\n \"EntitlementId\": \"entitlement-2\",\n \"RemainingTimeMinutes\": 45,\n \"FirstReadTime\": \"2026-01-25T14:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": []\n}"
docs: "## Sync Multiple Books Progress\n\nSynchronizes reading progress for multiple books in a single request.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information (Model: \"Kobo Aura\")\n\n**Request Body:**\n- `ReadingSync` (array): Multiple progress items\n - Each item contains: ContentId, PercentRead, EntitlementId, etc.\n- `BookmarkSync` (array): Empty for progress-only batch\n\n**Response:**\n- `total` (integer): Total items in request\n- `synced` (integer): Successfully synced\n- `failed` (integer): Failed items\n- `results` (array): Per-item results\n - `ContentId` (string): Book UUID\n - `status` (string): `synced`, `failed`, `skipped`\n - `error` (string, optional): Error message if failed\n\n**Status Codes:**\n- 200: Batch sync completed\n- 207: Multi-status (some succeeded, some failed)\n- 401: Unauthorized\n- 413: Payload too large\
\ (>1MB)\n\n**Batch Sync Advantages:**\n- Efficient sync of entire library\n- Reduces HTTP overhead\n- Faster for devices with many books\n- Atomic operation (all or nothing by default)\n\n**Kobo Batch Sync Behavior:**\n- Triggered when device connects after being offline\n- Occurs during manual \"Sync now\" operation\n- Limited to 100 books per request\n- Progress updates shown on device\n- Failed items retried individually\n\n**Performance:**\n- Typical batch: 10-50 books in 1-3 seconds\n- Large batch: 50-100 books in 3-8 seconds\n- Timeout: 30 seconds\n- Rate limit: 10 batches per minute per device\n\n**Use Cases:**\n- Initial device sync after registration\n- Catch-up sync after extended offline period\n- Library-wide progress update\n- Pre-sync before device firmware update"
@@ -2,83 +2,17 @@ info:
name: Sync Progress with Bookmarks
type: http
seq: 2
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
body:
type: json
json:
ReadingSync:
- ContentId: book-uuid
PercentRead: 42.3
EntitlementId: entitlement-id
RemainingTimeMinutes: 138
FirstReadTime: '2026-01-25T10:00:00Z'
LastModified: '2026-01-30T20:00:00Z'
BookmarkSync:
- ContentId: book-uuid
BookmarkText: highlighted text passage
BookmarkType: annotation
BookmarkTitle: Chapter 3
docs: |-
## Sync Progress with Bookmarks
Synchronizes reading progress and highlights/annotations from Kobo device.
**Method:** POST
**Endpoint:** /api/sync/kobo/markup
**Authentication:** Bearer token
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: Device information JSON
**Request Body:**
- `ReadingSync` (array): Progress items (see Sync Reading Progress)
- `BookmarkSync` (array): Highlights and annotations
- `ContentId` (string): Book UUID
- `BookmarkText` (string): Highlighted text or note content
- `BookmarkType` (string): Type of bookmark
- `annotation`: Highlighted text
- `note`: Personal note
- `bookmark`: Location bookmark
- `BookmarkTitle` (string): Reference (e.g., chapter name)
- `ChapterID` (string, optional): Chapter identifier
- `DateCreated` (string, optional): Creation timestamp
**Response:**
- `progress_synced` (integer): Progress items synced
- `bookmarks_synced` (integer): Bookmark items synced
- `conflicts_resolved` (integer): Number of conflicts auto-resolved
- `timestamp` (string): Sync timestamp
- `details` (object): Sync breakdown by type
**Status Codes:**
- 200: Successful sync
- 401: Unauthorized
- 400: Invalid data
**Kobo Highlight Features:**
- 5 highlight colors (yellow, green, blue, pink, orange)
- Chapter-based organization
- Linked to reading progress
- Appears in Kobo "Notebook" view
- Can be exported from device
- Syncs across all user devices
**Annotation Sync:**
- Highlight text preserved exactly
- Color mapped to system colors
- Chapter reference maintained
- Location data converted to standard format
- Notes attached to highlights synced separately
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 42.3,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 138,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"highlighted text passage\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\"\n }\n ]\n}"
docs: "## Sync Progress with Bookmarks\n\nSynchronizes reading progress and highlights/annotations from Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information JSON\n\n**Request Body:**\n- `ReadingSync` (array): Progress items (see Sync Reading Progress)\n- `BookmarkSync` (array): Highlights and annotations\n - `ContentId` (string): Book UUID\n - `BookmarkText` (string): Highlighted text or note content\n - `BookmarkType` (string): Type of bookmark\n - `annotation`: Highlighted text\n - `note`: Personal note\n - `bookmark`: Location bookmark\n - `BookmarkTitle` (string): Reference (e.g., chapter name)\n - `ChapterID` (string, optional): Chapter identifier\n - `DateCreated` (string, optional): Creation timestamp\n\n**Response:**\n- `progress_synced` (integer): Progress items synced\n- `bookmarks_synced` (integer): Bookmark\
\ items synced\n- `conflicts_resolved` (integer): Number of conflicts auto-resolved\n- `timestamp` (string): Sync timestamp\n- `details` (object): Sync breakdown by type\n\n**Status Codes:**\n- 200: Successful sync\n- 401: Unauthorized\n- 400: Invalid data\n\n**Kobo Highlight Features:**\n- 5 highlight colors (yellow, green, blue, pink, orange)\n- Chapter-based organization\n- Linked to reading progress\n- Appears in Kobo \"Notebook\" view\n- Can be exported from device\n- Syncs across all user devices\n\n**Annotation Sync:**\n- Highlight text preserved exactly\n- Color mapped to system colors\n- Chapter reference maintained\n- Location data converted to standard format\n- Notes attached to highlights synced separately"
@@ -2,83 +2,18 @@ info:
name: Sync Reading Progress
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
body:
type: json
json:
ReadingSync:
- ContentId: book-uuid-here
PercentRead: 45.6
EntitlementId: entitlement-id-here
RemainingTimeMinutes: 120
FirstReadTime: '2026-01-25T10:00:00Z'
LastModified: '2026-01-30T20:00:00Z'
BookmarkSync: []
docs: |-
## Sync Kobo Reading Progress
Synchronizes reading progress from a Kobo device to the server using Bearer token authentication.
**Method:** POST
**Endpoint:** /api/sync/kobo/markup
**Authentication:** Bearer token (in Authorization header)
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: JSON-encoded device info
- `DeviceId`: Kobo device identifier
- `Model`: Device model (e.g., "Kobo Clara", "Kobo Libra", "Kobo Aura")
**Request Body:**
- `ReadingSync` (array): Reading progress items
- `ContentId` (string): Book/Content UUID
- `PercentRead` (number): Reading progress 0-100
- `EntitlementId` (string): Kobo entitlement ID
- `RemainingTimeMinutes` (integer): Estimated reading time remaining
- `FirstReadTime` (string): ISO 8601 timestamp when first opened
- `LastModified` (string): ISO 8601 timestamp of last progress update
- `BookmarkSync` (array): Empty array for progress-only sync
**Response:**
- `synced` (integer): Number of items synced
- `failed` (integer): Number of items that failed to sync
- `timestamp` (string): Server timestamp of sync
- `books` (array): Synced book data
- `ContentId` (string): Book UUID
- `status` (string): `synced`, `failed`, `skipped`
- `server_percent` (number): Server-side progress (for conflict detection)
**Status Codes:**
- 200: Sync successful
- 401: Invalid device token
- 403: Device not approved
- 400: Invalid request format
**Authentication Methods:**
This endpoint uses **Bearer token authentication** (token in Authorization header).
Alternative: Use `/sync/kobo/{token}/markup` with token in URL path.
**Kobo Sync Features:**
- Native Kobo sync protocol
- Supports Kobo Clara, Libra, Aura, Forma, Sage, Elipsa
- Progress percentage tracking
- Reading time estimation
- Cross-device synchronization
- Automatic conflict resolution (most recent wins)
**Sync Frequency:**
- Kobo devices auto-sync every 15-30 minutes when connected to WiFi
- Manual sync available from device settings
- Sync triggers on: device wake, book close, WiFi connection
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid-here\",\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id-here\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": []\n}"
docs: "## Sync Kobo Reading Progress\n\nSynchronizes reading progress from a Kobo device to the server using Bearer token authentication.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token (in Authorization header)\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: JSON-encoded device info\n - `DeviceId`: Kobo device identifier\n - `Model`: Device model (e.g., \"Kobo Clara\", \"Kobo Libra\", \"Kobo Aura\")\n\n**Request Body:**\n- `ReadingSync` (array): Reading progress items\n - `ContentId` (string): Book/Content UUID\n - `PercentRead` (number): Reading progress 0-100\n - `EntitlementId` (string): Kobo entitlement ID\n - `RemainingTimeMinutes` (integer): Estimated reading time remaining\n - `FirstReadTime` (string): ISO 8601 timestamp when first opened\n - `LastModified` (string): ISO 8601 timestamp of last progress update\n- `BookmarkSync` (array): Empty array for progress-only sync\n\n**Response:**\n\
- `synced` (integer): Number of items synced\n- `failed` (integer): Number of items that failed to sync\n- `timestamp` (string): Server timestamp of sync\n- `books` (array): Synced book data\n - `ContentId` (string): Book UUID\n - `status` (string): `synced`, `failed`, `skipped`\n - `server_percent` (number): Server-side progress (for conflict detection)\n\n**Status Codes:**\n- 200: Sync successful\n- 401: Invalid device token\n- 403: Device not approved\n- 400: Invalid request format\n\n**Authentication Methods:**\nThis endpoint uses **Bearer token authentication** (token in Authorization header).\nAlternative: Use `/sync/kobo/{token}/markup` with token in URL path.\n\n**Kobo Sync Features:**\n- Native Kobo sync protocol\n- Supports Kobo Clara, Libra, Aura, Forma, Sage, Elipsa\n- Progress percentage tracking\n- Reading time estimation\n- Cross-device synchronization\n- Automatic conflict resolution (most recent wins)\n\n**Sync Frequency:**\n- Kobo devices auto-sync every 15-30 minutes\
\ when connected to WiFi\n- Manual sync available from device settings\n- Sync triggers on: device wake, book close, WiFi connection"
@@ -2,91 +2,18 @@ info:
name: Sync Single Bookmark
type: http
seq: 5
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
body:
type: json
json:
ContentId: book-uuid
BookmarkText: Bookmarked passage
BookmarkType: annotation
BookmarkTitle: Chapter 3
docs: |-
## Sync Single Bookmark
Synchronizes an individual bookmark/highlight from Kobo device.
**Method:** POST
**Endpoint:** /api/sync/kobo/bookmark
**Authentication:** Bearer token
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: Device information JSON
**Request Body:**
- `ContentId` (string): Book UUID
- `BookmarkText` (string): Highlighted text or bookmark description
- `BookmarkType` (string): Type of bookmark
- `annotation`: Highlighted text passage
- `note`: Personal note
- `bookmark`: Location marker
- `BookmarkTitle` (string): Reference title (e.g., chapter name)
- `ChapterID` (string, optional): Chapter identifier
- `DateCreated` (string, optional): ISO 8601 timestamp
- `highlight_color` (string, optional): Color name (yellow, green, blue, pink, orange)
**Response:**
- `id` (string): Server bookmark ID
- `ContentId` (string): Associated book UUID
- `status` (string): `created`, `updated`, `skipped` (duplicate)
- `timestamp` (string): Server timestamp
- `url` (string): API URL to retrieve bookmark
**Status Codes:**
- 201: Bookmark created
- 200: Bookmark updated (duplicate found)
- 409: Duplicate bookmark (unchanged)
- 401: Unauthorized
- 400: Invalid bookmark data
**Single Bookmark Sync vs Batch:**
- **Single bookmark endpoint:** Real-time, immediate sync
- **Batch markup endpoint:** Deferred, periodic sync
- Use single when user explicitly creates highlight
- Use batch for periodic background sync
**Kobo Trigger:**
- User highlights text → immediate single sync
- User adds note → immediate single sync
- Device goes online → batch sync of all changes
**Duplicate Detection:**
- Same ContentId + similar BookmarkText + same location
- Updates existing if text modified
- Skips if identical bookmark exists
- Preserves creation date of original
**Use Cases:**
- Real-time highlight sync
- Instant note backup
- Immediate annotation sharing
- Quick single annotation update
- Testing annotation sync
**Notes:**
- Much faster than full markup sync
- Lower bandwidth usage
- Ideal for intermittent connectivity
- Can be called multiple times safely
data: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Bookmarked passage\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\"\n}"
docs: "## Sync Single Bookmark\n\nSynchronizes an individual bookmark/highlight from Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/bookmark\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information JSON\n\n**Request Body:**\n- `ContentId` (string): Book UUID\n- `BookmarkText` (string): Highlighted text or bookmark description\n- `BookmarkType` (string): Type of bookmark\n - `annotation`: Highlighted text passage\n - `note`: Personal note\n - `bookmark`: Location marker\n- `BookmarkTitle` (string): Reference title (e.g., chapter name)\n- `ChapterID` (string, optional): Chapter identifier\n- `DateCreated` (string, optional): ISO 8601 timestamp\n- `highlight_color` (string, optional): Color name (yellow, green, blue, pink, orange)\n\n**Response:**\n- `id` (string): Server bookmark ID\n- `ContentId` (string): Associated book UUID\n- `status` (string): `created`, `updated`, `skipped` (duplicate)\n\
- `timestamp` (string): Server timestamp\n- `url` (string): API URL to retrieve bookmark\n\n**Status Codes:**\n- 201: Bookmark created\n- 200: Bookmark updated (duplicate found)\n- 409: Duplicate bookmark (unchanged)\n- 401: Unauthorized\n- 400: Invalid bookmark data\n\n**Single Bookmark Sync vs Batch:**\n- **Single bookmark endpoint:** Real-time, immediate sync\n- **Batch markup endpoint:** Deferred, periodic sync\n- Use single when user explicitly creates highlight\n- Use batch for periodic background sync\n\n**Kobo Trigger:**\n- User highlights text → immediate single sync\n- User adds note → immediate single sync\n- Device goes online → batch sync of all changes\n\n**Duplicate Detection:**\n- Same ContentId + similar BookmarkText + same location\n- Updates existing if text modified\n- Skips if identical bookmark exists\n- Preserves creation date of original\n\n**Use Cases:**\n- Real-time highlight sync\n- Instant note backup\n- Immediate annotation sharing\n- Quick single annotation\
\ update\n- Testing annotation sync\n\n**Notes:**\n- Much faster than full markup sync\n- Lower bandwidth usage\n- Ideal for intermittent connectivity\n- Can be called multiple times safely"
@@ -2,105 +2,17 @@ info:
name: Sync with Annotations
type: http
seq: 4
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Libra"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Libra"}'
body:
type: json
json:
ReadingSync:
- ContentId: book-uuid
PercentRead: 55.0
EntitlementId: entitlement-id
RemainingTimeMinutes: 120
FirstReadTime: '2026-01-25T10:00:00Z'
LastModified: '2026-01-30T20:00:00Z'
BookmarkSync:
- ContentId: book-uuid
BookmarkText: Important quote
BookmarkType: annotation
BookmarkTitle: Chapter 4 - The Truth
- ContentId: book-uuid
BookmarkText: Another quote
BookmarkType: annotation
BookmarkTitle: Chapter 5
- ContentId: book-uuid
BookmarkText: Note to myself
BookmarkType: note
BookmarkTitle: Personal note
docs: |-
## Sync with Multiple Annotations
Synchronizes reading progress with multiple highlights and notes.
**Method:** POST
**Endpoint:** /api/sync/kobo/markup
**Authentication:** Bearer token
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: Device info (Model: "Kobo Libra")
**Request Body:**
- `ReadingSync` (array): Single book progress
- `BookmarkSync` (array): Multiple annotations
- Can include highlights (annotation type)
- Can include notes (note type)
- Each has: ContentId, BookmarkText, BookmarkType, BookmarkTitle
**Response:**
- `progress_synced` (boolean): Progress update status
- `annotations_synced` (integer): Number of annotations synced
- `highlights_count` (integer): Highlights synced
- `notes_count` (integer): Notes synced
- `conflicts` (array): Any annotation conflicts resolved
- `timestamp` (string): Sync completion time
**Status Codes:**
- 200: Successful sync
- 401: Unauthorized
- 400: Invalid annotation data
**Kobo Annotation Types:**
- **Highlights:** Selected text passages
- 5 preset colors available
- Can have chapter titles
- Exportable to PDF/Mobile
- **Notes:** Personal annotations
- Free-form text
- Can be attached to highlights
- Separate from highlights
- **Bookmarks:** Location markers
- Chapter positions
- Quick navigation
**Sync Behavior:**
- Duplicates detected by content matching
- Most recent edit wins conflicts
- Annotations linked to book content
- Chapter references preserved
- Order maintained from device
**Kobo Notebook Export:**
- All annotations appear in Kobo "Notebook"
- Can be exported to PDF
- Can be exported to Mobile (text)
- Organized by book
- Shows highlight context
**Use Cases:**
- Study and research
- Book club discussion prep
- Content review
- Sharing insights
- Personal learning archive
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 55.0,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Important quote\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 4 - The Truth\"\n },\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Another quote\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 5\"\n },\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Note to myself\",\n \"BookmarkType\": \"note\",\n \"BookmarkTitle\": \"Personal note\"\n }\n ]\n}"
docs: "## Sync with Multiple Annotations\n\nSynchronizes reading progress with multiple highlights and notes.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device info (Model: \"Kobo Libra\")\n\n**Request Body:**\n- `ReadingSync` (array): Single book progress\n- `BookmarkSync` (array): Multiple annotations\n - Can include highlights (annotation type)\n - Can include notes (note type)\n - Each has: ContentId, BookmarkText, BookmarkType, BookmarkTitle\n\n**Response:**\n- `progress_synced` (boolean): Progress update status\n- `annotations_synced` (integer): Number of annotations synced\n- `highlights_count` (integer): Highlights synced\n- `notes_count` (integer): Notes synced\n- `conflicts` (array): Any annotation conflicts resolved\n- `timestamp` (string): Sync completion time\n\n**Status Codes:**\n- 200: Successful sync\n- 401: Unauthorized\n- 400: Invalid\
\ annotation data\n\n**Kobo Annotation Types:**\n- **Highlights:** Selected text passages\n - 5 preset colors available\n - Can have chapter titles\n - Exportable to PDF/Mobile\n- **Notes:** Personal annotations\n - Free-form text\n - Can be attached to highlights\n - Separate from highlights\n- **Bookmarks:** Location markers\n - Chapter positions\n - Quick navigation\n\n**Sync Behavior:**\n- Duplicates detected by content matching\n- Most recent edit wins conflicts\n- Annotations linked to book content\n- Chapter references preserved\n- Order maintained from device\n\n**Kobo Notebook Export:**\n- All annotations appear in Kobo \"Notebook\"\n- Can be exported to PDF\n- Can be exported to Mobile (text)\n- Organized by book\n- Shows highlight context\n\n**Use Cases:**\n- Study and research\n- Book club discussion prep\n- Content review\n- Sharing insights\n- Personal learning archive"
+2 -32
View File
@@ -8,38 +8,8 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"BookmarkSync\": [\n {\n \"BookmarkId\": \"bookmark_2\"\
,\n \"ContentId\": \"kobo_xyz789\",\n \"BookmarkText\": \"Important\
\ note\",\n \"BookmarkType\": \"bookmark\",\n \"DateCreated\"\
: \"2026-01-31T12:00:00Z\""
data: "{\n \"BookmarkSync\": [\n {\n \"BookmarkId\": \"bookmark_2\",\n \"ContentId\": \"kobo_xyz789\",\n \"BookmarkText\": \"Important note\",\n \"BookmarkType\": \"bookmark\",\n \"DateCreated\": \"2026-01-31T12:00:00Z\""
headers:
- key: Authorization
value: Bearer {{device_token
docs: |-
## Kobo Bookmark Sync
Synchronizes bookmarks from a Kobo device to the Bookhoard server.
**Method:** POST
**Endpoint:** /api/v1/kobo/bookmark
**Authentication:** Bearer token (device token)
**Request Body:**
- `BookmarkSync` (array): Array of bookmark objects
- `BookmarkId` (string): Unique bookmark ID
- `ContentId` (string): Book/content ID
- `BookmarkText` (string): Bookmark text or note
- `BookmarkType` (string): Type (bookmark, highlight, note)
- `DateCreated` (string): ISO 8601 timestamp
**Response:**
- `Status` (string): Sync status (Success, Partial)
- `BookmarksSynced` (number): Number of bookmarks synced
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 500: Internal server error
docs: "## Kobo Bookmark Sync\n\n Synchronizes bookmarks from a Kobo device to the Bookhoard server.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/kobo/bookmark\n\n **Authentication:** Bearer token (device token)\n\n **Request Body:**\n - `BookmarkSync` (array): Array of bookmark objects\n - `BookmarkId` (string): Unique bookmark ID\n - `ContentId` (string): Book/content ID\n - `BookmarkText` (string): Bookmark text or note\n - `BookmarkType` (string): Type (bookmark, highlight, note)\n - `DateCreated` (string): ISO 8601 timestamp\n\n **Response:**\n - `Status` (string): Sync status (Success, Partial)\n - `BookmarksSynced` (number): Number of bookmarks synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
+2 -30
View File
@@ -8,36 +8,8 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"unlinked_book_id\": \"{{unlinked_book_id"
data: "{\n \"unlinked_book_id\": \"{{unlinked_book_id"
headers:
- key: Authorization
value: Bearer {{user_token
docs: |-
## Link Unlinked Book - Manual Resolution
Manually links an unlinked book to a media item in the library.
**Method:** POST
**Endpoint:** /api/sync/link-book
**Authentication:** Bearer token
**Request Body:**
- `unlinked_book_id` (string): Unlinked book UUID
- `media_item_id` (string): Media item UUID to link to
- `confidence_score` (number): Match confidence (0-1, 1.0 for manual)
**Response:**
- `status` (string): Link status (linked)
- `unlinked_book_id` (string): Unlinked book UUID
- `media_item_id` (string): Media item UUID
- `message` (string): Success message
**Status Codes:**
- 200: Success - book linked
- 400: Invalid request
- 401: Unauthorized
- 404: Book or media item not found
- 500: Internal server error
docs: "## Link Unlinked Book - Manual Resolution\n\n Manually links an unlinked book to a media item in the library.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/link-book\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1, 1.0 for manual)\n\n **Response:**\n - `status` (string): Link status (linked)\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID\n - `message` (string): Success message\n\n **Status Codes:**\n - 200: Success - book linked\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Book or media item not found\n - 500: Internal server error"
@@ -8,18 +8,8 @@ http:
auth: none
body:
type: json
jsonBody: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Highlighted\
\ text\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"\
Chapter 3\""
data: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Highlighted text\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\""
headers:
- key: Content-Type
value: application/json
docs: |-
## Sync Bookmark - URL Path Token
Synchronizes bookmarks and annotations from Kobo device using token in URL path.
**Method:** POST
**Endpoint:** /sync/kobo/{kobo_device_token
docs: "## Sync Bookmark - URL Path Token\n\n Synchronizes bookmarks and annotations from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
@@ -8,19 +8,8 @@ http:
auth: none
body:
type: json
jsonBody: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\"\
,\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id\"\
,\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\"\
,\n \"LastModified\": \"2026-01-30T20:00:00Z\""
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\""
headers:
- key: Content-Type
value: application/json
docs: |-
## Sync Reading Progress - URL Path Token
Synchronizes reading progress from Kobo device using token in URL path.
**Method:** POST
**Endpoint:** /sync/kobo/{kobo_device_token
docs: "## Sync Reading Progress - URL Path Token\n\n Synchronizes reading progress from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
@@ -3,18 +3,8 @@ docs: "## Checkpoint Sync\n\nIncremental sync using checkpoint-based change trac
\ Repeat from step 3\n\n**Sync Optimization:**\n- Only books with progress changes\n- Skips unmodified books\n- Delta transfer\n- Compression for large payloads\n- Batch processing\n\n**Failure Handling:**\n- Checkpoint ID preserved on failure\n- Retry with same checkpoint\n- Full sync if checkpoint expired\n- Checkpoint validity: 24 hours\n- Auto-fallback to full sync\n\n**Performance:**\n- Small changes (1-10 books): 100-300ms\n- Medium changes (10-50 books): 300ms-1s\n- Large changes (50-100 books): 1-3s\n- Typical: 5-10x faster than full sync\n\n**When to Use:**\n- Default sync mode for most users\n- Periodic background sync\n- Large library management\n- Mobile/network-constrained environments\n- Battery-powered devices\n\n**Configuration:**\n- Checkpoint expiration: 24 hours\n- Max history: 100 checkpoints\n- Auto-cleanup of old checkpoints\n- Configurable sync interval"
http:
body:
json:
books:
- chapter: 3
percentage: 0.45
uuid: '{{media_item_id}}'
- chapter: 8
percentage: 0.75
uuid: '{{media_item_id}}'
checkpoint_id: checkpoint-uuid
since_timestamp: '2026-01-30T19:00:00Z'
sync_mode: checkpoint
type: json
data: "{\n \"books\": [\n {\n \"chapter\": 3,\n \"percentage\": 0.45,\n \"uuid\": \"{{media_item_id}}\"\n },\n {\n \"chapter\": 8,\n \"percentage\": 0.75,\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"checkpoint_id\": \"checkpoint-uuid\",\n \"since_timestamp\": \"2026-01-30T19:00:00Z\",\n \"sync_mode\": \"checkpoint\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -3,14 +3,8 @@ docs: "## Immediate Sync - Page Turn\n\nReal-time progress sync triggered immedi
- Research and study\n- Testing sync functionality\n- When power source available\n\n**When NOT to Use:**\n- Battery conservation needed\n- Unstable network\n- Extended reading sessions\n- Background sync preferred"
http:
body:
json:
books:
- chapter: 3
percentage: 0.45678
timestamp: '2026-01-30T20:00:00Z'
uuid: '{{media_item_id}}'
sync_mode: immediate
type: json
data: "{\n \"books\": [\n {\n \"chapter\": 3,\n \"percentage\": 0.45678,\n \"timestamp\": \"2026-01-30T20:00:00Z\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"sync_mode\": \"immediate\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -1,8 +1,8 @@
docs: "## KOReader Sync Annotations - Per-Book SHA-256\n\n Synchronizes annotations (highlights) from KOReader with per-annotation SHA-256 hashes for multi-book sync.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/bookmarks\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `book_uuid` (string): Primary book UUID\n - `highlights` (array): Array of highlight objects\n - `text` (string): Highlighted text\n - `pos0`, `pos1` (string): EPUB CFI positions\n - `color` (string): Highlight color (hex)\n - `page` (number): Page number\n - `book_sha256` (string): SHA-256 hash for this specific book\n\n **Response:**\n - `highlights_synced` (number): Number of highlights synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Each highlight can include its own book_sha256, allowing annotations from multiple books in a single request."
http:
body:
jsonBody: "{\n \"book_uuid\": \"{{book_uuid"
type: json
data: "{\n \"book_sha256\": \"{{book_sha256}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"p1\",\n \"text\": \"Per-book annotation\",\n \"type\": \"bookmark\"\n }\n ]\n}"
headers: []
method: POST
url: '{{base_url}}/api/sync/koreader/bookmarks'
@@ -1,8 +1,8 @@
docs: "## KOReader Sync Bookmarks - SHA-256\n\n Synchronizes bookmarks, notes, and highlights from KOReader using SHA-256 hash for book identification.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/bookmarks\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `book_sha256` (string): SHA-256 hash of book file\n - `bookmarks` (array): Array of bookmarks\n - `notes` (array): Array of notes\n - `highlights` (array): Array of highlights\n\n **Response:**\n - `sync_status` (string): Sync status\n - `total_synced` (number): Total items synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
http:
body:
jsonBody: "{\n \"book_sha256\": \"{{book_sha256"
type: json
data: "{\n \"book_sha256\": \"{{book_sha256}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"p1\",\n \"text\": \"SHA-256 bookmark\",\n \"type\": \"bookmark\"\n }\n ]\n}"
headers: []
method: POST
url: '{{base_url}}/api/sync/koreader/bookmarks'
@@ -3,20 +3,8 @@ docs: "## Sync KOReader Bookmarks\n\nSynchronizes bookmarks separately from prog
\ bookmark\" menu\n- Shown in \"Bookmarks\" panel\n- Quick access via \"Go to bookmark\"\n- Exportable to JSON\n- Can be edited/deleted\n\n**Use Cases:**\n- Quick navigation aids\n- Chapter markers\n- Important passages\n- Reading progress points\n- Study session markers"
http:
body:
json:
books:
- bookmarks:
- chapter: 3
datetime: '2026-01-30T19:55:00Z'
notes: Marked this chapter as important
page: 45
pos0: epubcfi(/6/4/2:15)
pos1: epubcfi(/6/4/2:20)
text: Important passage
type: bookmark
uuid: '{{media_item_id}}'
library_id: optional-library-uuid
type: json
data: "{\n \"book_uuid\": \"{{media_item_id}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"epubcfi(/6/4/2:15)\",\n \"pos1\": \"epubcfi(/6/4/2:20)\",\n \"text\": \"Important passage\",\n \"type\": \"bookmark\"\n }\n ]\n}"
headers:
- key: Content-Type
value: application/json
@@ -4,10 +4,7 @@ docs: "## Sync KOReader Highlights\n\nSynchronizes text highlights separately fr
http:
body:
type: json
jsonBody: "{\n \"book_uuid\": \"786b9c39-e8c3-47ab-a48a-c7f6cd769930\",\n \"highlights\": [\n {\n \"datetime\": \"2026-01-30T19:50:00Z\",\n \"text\": \"bruno sweep highlight\",\n \"chapter\": 1,\n \"page\": 1,\n \"pos0\": \"1\",\n \"pos1\": \"9\",\n \"color\": \"#ffff00\"\n }\n ]\n}"
headers:
- key: Content-Type
value: application/json
data: "{\n \"book_uuid\": \"786b9c39-e8c3-47ab-a48a-c7f6cd769930\",\n \"highlights\": [\n {\n \"datetime\": \"2026-01-30T19:50:00Z\",\n \"text\": \"bruno sweep highlight\",\n \"chapter\": 1,\n \"page\": 1,\n \"pos0\": \"1\",\n \"pos1\": \"9\",\n \"color\": \"#ffff00\"\n }\n ]\n}"
method: POST
url: '{{base_url}}/api/sync/koreader/bookmarks'
auth:
@@ -3,8 +3,8 @@ docs: "## Sync KOReader Notes\n\nSynchronizes user notes separately from highlig
\ via \"Add note\" option\n- Edited in note editor\n- Shown in \"Notes\" panel\n- Can be organized by chapter\n- Export functionality available\n- Search support\n\n**Advanced Features:**\n- **Markdown**: Bold, italic, lists (some versions)\n- **Tags**: User-defined tags (via plugins)\n- **Links**: Internal/external links\n- **Formatting**: Rich text in newer versions\n\n**Use Cases:**\n- Study notes\n- Personal reflections\n- Academic annotations\n- Research insights\n- Book club discussion prep\n- Knowledge management"
http:
body:
jsonBody: "{\n \"book_uuid\": \"{{media_item_id}}\",\n \"notes\": [\n {\n \"datetime\": \"2026-01-30T19:52:00Z\",\n \"notes\": \"A personal note about this chapter\",\n \"chapter\": 4,\n \"page\": 57,\n \"pos0\": \"3\"\n }\n ]\n}"
type: json
data: "{\n \"book_uuid\": \"{{media_item_id}}\",\n \"notes\": [\n {\n \"datetime\": \"2026-01-30T19:52:00Z\",\n \"notes\": \"A personal note about this chapter\",\n \"chapter\": 4,\n \"page\": 57,\n \"pos0\": \"3\"\n }\n ]\n}"
headers:
- key: Content-Type
value: application/json
@@ -1,8 +1,8 @@
docs: "## KOReader Sync Progress - SHA-256 Only\n\n Synchronizes reading progress using only SHA-256 hash for book identification (when UUID is not available).\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/progress\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `sync_mode` (string): Sync mode (immediate, deferred)\n - `books` (array): Array of book progress objects\n - `sha256` (string): SHA-256 hash of book file\n - `file_path` (string): Path to book file\n - `percentage` (number): Progress percentage\n - `page` (number): Current page\n - `total_pages` (number): Total pages\n\n **Response:**\n - `sync_status` (string): Sync status\n - `books_synced` (number): Number of books synced\n\n **Status Codes:**\n - 200: Success\n - 202: Accepted\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Use this when book UUID is not available, falling back to SHA-256 hash for identification."
http:
body:
jsonBody: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"sha256\": \"{{book_sha256"
type: json
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"sha256\": \"{{book_sha256}}\",\n \"percentage\": 0.5\n }\n ]\n}"
headers: []
method: POST
url: '{{base_url}}/api/sync/koreader/progress'
@@ -2,8 +2,8 @@ docs: "## KOReader Sync Progress - SHA-256\n\n Synchronizes reading progress fr
\ (number): Number of books synced\n\n **Status Codes:**\n - 200: Success\n - 202: Accepted - processing\n - 401: Unauthorized\n - 500: Internal server error"
http:
body:
jsonBody: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"uuid\": \"{{book_uuid"
type: json
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"sha256\": \"{{book_sha256}}\",\n \"percentage\": 0.5\n }\n ]\n}"
headers: []
method: POST
url: '{{base_url}}/api/sync/koreader/progress'
@@ -2,28 +2,8 @@ docs: "## Sync KOReader Progress - Multiple Books\n\nSynchronizes reading progre
\ Batch Behavior:**\n- Triggered on device wake from sleep\n- Occurs during \"Sync now\" operation\n- Runs on WiFi connection\n- Limited to 100 books per request\n- Automatic retry on failed books\n\n**Performance:**\n- Small batch (2-10 books): 200-500ms\n- Medium batch (10-50 books): 500ms-2s\n- Large batch (50-100 books): 2-5s\n- Timeout: 30 seconds\n\n**Use Cases:**\n- Device initialization sync\n- Periodic background sync\n- Post-offline catch-up sync\n- Library-wide progress update\n- Before firmware update"
http:
body:
json:
books:
- authors:
- Author One
chapter: 1
epubcfi: epubcfi(/6/4/2:10)
last_read: '2026-01-30T19:00:00Z'
percentage: 0.25
progress: 0.25
title: Book One
uuid: '{{media_item_id}}'
- authors:
- Author Two
chapter: 8
epubcfi: epubcfi(/6/4/2:50)
last_read: '2026-01-30T20:00:00Z'
percentage: 0.75
progress: 0.75
title: Book Two
uuid: '{{media_item_id}}'
library_id: optional-library-uuid
type: json
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author One\"\n ],\n \"chapter\": 1,\n \"epubcfi\": \"epubcfi(/6/4/2:10)\",\n \"last_read\": \"2026-01-30T19:00:00Z\",\n \"percentage\": 0.25,\n \"progress\": 0.25,\n \"title\": \"Book One\",\n \"uuid\": \"{{media_item_id}}\"\n },\n {\n \"authors\": [\n \"Author Two\"\n ],\n \"chapter\": 8,\n \"epubcfi\": \"epubcfi(/6/4/2:50)\",\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.75,\n \"progress\": 0.75,\n \"title\": \"Book Two\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -3,20 +3,8 @@ docs: "## Sync KOReader Progress - Single Book\n\nSynchronizes reading progress
- Real-time page turn sync\n- Progress backup\n- Cross-device continuity\n- Reading time tracking\n- Chapter completion detection"
http:
body:
json:
books:
- authors:
- Author Name
chapter: 3
character: 15432
epubcfi: epubcfi(/6/4/2:15)
last_read: '2026-01-30T20:00:00Z'
percentage: 0.45
progress: 0.45
title: Book Title
uuid: '{{media_item_id}}'
library_id: optional-library-uuid
type: json
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"chapter\": 3,\n \"character\": 15432,\n \"epubcfi\": \"epubcfi(/6/4/2:15)\",\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.45,\n \"progress\": 0.45,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -3,26 +3,8 @@ docs: "## Sync Progress with Bookmarks\n\nSynchronizes reading progress with boo
- Searchable by content\n\n**Use Cases:**\n- Study and research\n- Content review\n- Passage tracking\n- Quick navigation\n- Cross-device bookmark access"
http:
body:
json:
books:
- authors:
- Author Name
bookmarks:
- chapter: 3
datetime: '2026-01-30T19:55:00Z'
notes: highlighted text
page: 45
pos0: epubcfi(/6/4/2:15)
pos1: epubcfi(/6/4/2:20)
text: highlighted text excerpt
type: highlight
last_read: '2026-01-30T20:00:00Z'
percentage: 0.45
progress: 0.45
title: Book Title
uuid: '{{media_item_id}}'
library_id: optional-library-uuid
type: json
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"notes\": \"highlighted text\",\n \"page\": 45,\n \"pos0\": \"epubcfi(/6/4/2:15)\",\n \"pos1\": \"epubcfi(/6/4/2:20)\",\n \"text\": \"highlighted text excerpt\",\n \"type\": \"highlight\"\n }\n ],\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.45,\n \"progress\": 0.45,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -3,29 +3,8 @@ docs: "## Sync Progress with Highlights and Notes\n\nSynchronizes reading progre
\ passages\n- Blue: Key concepts\n- Red: Critical information\n- Orange: Interesting quotes\n- Custom colors available\n\n**Sync Advantages:**\n- Separation allows granular control\n- Highlights sync without notes\n- Notes sync independently\n- Better conflict resolution\n- Efficient for large annotation sets\n\n**Use Cases:**\n- Academic research\n- Study groups\n- Content analysis\n- Personal knowledge management\n- Sharing insights"
http:
body:
json:
books:
- authors:
- Author Name
highlights:
- chapter: 4
datetime: '2026-01-30T19:50:00Z'
page_end: 79
page_start: 78
pos0: epubcfi(/6/4/2:20)
pos1: epubcfi(/6/4/2:30)
text: Important passage
last_read: '2026-01-30T20:00:00Z'
notes:
- chapter: 4
datetime: '2026-01-30T19:52:00Z'
text: My note about this chapter
percentage: 0.6
progress: 0.6
title: Book Title
uuid: '{{media_item_id}}'
library_id: optional-library-uuid
type: json
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"highlights\": [\n {\n \"chapter\": 4,\n \"datetime\": \"2026-01-30T19:50:00Z\",\n \"page_end\": 79,\n \"page_start\": 78,\n \"pos0\": \"epubcfi(/6/4/2:20)\",\n \"pos1\": \"epubcfi(/6/4/2:30)\",\n \"text\": \"Important passage\"\n }\n ],\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"notes\": [\n {\n \"chapter\": 4,\n \"datetime\": \"2026-01-30T19:52:00Z\",\n \"text\": \"My note about this chapter\"\n }\n ],\n \"percentage\": 0.6,\n \"progress\": 0.6,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
headers:
- key: Content-Type
value: application/json
@@ -2,8 +2,8 @@ docs: "## KOReader Sync Progress\n\n Synchronizes reading progress from a KORea
\ model identifier\n\n **Response:**\n - `sync_status` (string): Sync status (accepted, processing)\n - `books_synced` (number): Number of books synced\n\n **Status Codes:**\n - 202: Accepted - sync queued\n - 401: Unauthorized\n - 500: Internal server error"
http:
body:
jsonBody: "{\n \"library_id\": null,\n \"books\": [\n {\n \"uuid\": \"{{book_uuid"
type: json
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"uuid\": \"{{media_item_id}}\",\n \"percentage\": 0.45,\n \"chapter\": 3\n }\n ]\n}"
headers: []
method: POST
url: '{{base_url}}/api/sync/koreader/progress'
@@ -8,16 +8,8 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"media_item_ids\": [\n \"{{bookUUID1"
data: "{\n \"media_item_ids\": [\n \"{{bookUUID1"
headers:
- key: Authorization
value: Bearer {{userToken
docs: |-
## Add Books to Kobo Shelf
Add one or more books to a Kobo device shelf. Manages which books should be synced to a specific Kobo device. Supports multiple shelves for organization.
**Method:** POST
**Endpoint:** /api/devices/{deviceID
docs: "## Add Books to Kobo Shelf\n\n Add one or more books to a Kobo device shelf. Manages which books should be synced to a specific Kobo device. Supports multiple shelves for organization.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/{deviceID"
@@ -2,51 +2,15 @@ info:
name: Check Pending Registration
type: http
seq: 4
http:
method: POST
url: '{{base_url}}/api/devices/register/status'
auth: none
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
registration_id: registration-uuid-here
docs: |-
## Check Registration Status
Checks the current status of a device registration request.
**Method:** POST
**Endpoint:** /api/devices/register/status
**Authentication:** None
**Request Body:**
- `registration_id` (string): UUID received from registration request
**Response:**
- `registration_id` (string): The registration UUID
- `status` (string): Current status
- `pending`: Awaiting user approval
- `approved`: Registration approved, device ready
- `rejected`: Registration rejected by user
- `expired`: Registration expired (not approved in time)
- `device_name` (string): Name of the device
- `device_type` (string): Type of device
- `created_at` (string): Registration timestamp
- `updated_at` (string): Last status update timestamp
**Status Codes:**
- 200: Status retrieved successfully
- 404: Registration ID not found
- 400: Invalid registration ID format
**Polling Recommendations:**
- Poll every 5-10 seconds while status is `pending`
- Stop polling when status changes to `approved`, `rejected`, or `expired`
- Use exponential backoff for mobile devices to save battery
data: "{\n \"registration_id\": \"registration-uuid-here\"\n}"
docs: "## Check Registration Status\n\nChecks the current status of a device registration request.\n\n**Method:** POST\n\n**Endpoint:** /api/devices/register/status\n\n**Authentication:** None\n\n**Request Body:**\n- `registration_id` (string): UUID received from registration request\n\n**Response:**\n- `registration_id` (string): The registration UUID\n- `status` (string): Current status\n - `pending`: Awaiting user approval\n - `approved`: Registration approved, device ready\n - `rejected`: Registration rejected by user\n - `expired`: Registration expired (not approved in time)\n- `device_name` (string): Name of the device\n- `device_type` (string): Type of device\n- `created_at` (string): Registration timestamp\n- `updated_at` (string): Last status update timestamp\n\n**Status Codes:**\n- 200: Status retrieved successfully\n- 404: Registration ID not found\n- 400: Invalid registration ID format\n\n**Polling Recommendations:**\n- Poll every 5-10 seconds while status is `pending`\n\
- Stop polling when status changes to `approved`, `rejected`, or `expired`\n- Use exponential backoff for mobile devices to save battery"
@@ -8,30 +8,5 @@ http:
auth: none
body:
type: json
jsonBody: "{\n \"registration_id\": \"{{registrationId}}"
docs: |-
## Check Registration Status
Checks the current status of a device registration request.
**Method:** POST
**Endpoint:** /api/devices/register/status
**Authentication:** None
**Request Body:**
- `registration_id` (string, required): Registration request ID
**Response:**
- `status` (string): Registration status (pending, approved, rejected, expired)
- `device_name` (string): Device name
- `device_type` (string): Device type
- `created_at` (string): Request timestamp
- `expires_at` (string): Expiration timestamp
**Status Codes:**
- 200: Success
- 404: Registration ID not found
- 410: Registration expired
data: "{\n \"registration_id\": \"{{registrationId}}"
docs: "## Check Registration Status\n\n Checks the current status of a device registration request.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register/status\n\n **Authentication:** None\n\n **Request Body:**\n - `registration_id` (string, required): Registration request ID\n\n **Response:**\n - `status` (string): Registration status (pending, approved, rejected, expired)\n - `device_name` (string): Device name\n - `device_type` (string): Device type\n - `created_at` (string): Request timestamp\n - `expires_at` (string): Expiration timestamp\n\n **Status Codes:**\n - 200: Success\n - 404: Registration ID not found\n - 410: Registration expired"
@@ -8,48 +8,12 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"file_path\": \"/mnt/sd/books/my-book.kepub.epub\",\n \"\
media_item_id\": \"{{media_item_id"
data: "{\n \"file_path\": \"/mnt/sd/books/my-book.kepub.epub\",\n \"media_item_id\": \"{{media_item_id"
headers:
- key: Content-Type
value: application/json
runtime:
scripts:
- type: tests
code: "test_create_device_file_alias_success(status, headers, body) {\n if\
\ (status !== 201 && status !== 200) {\n throw new Error(\"Expected status\
\ 201 or 200, got \" + status);"
docs: |-
## Create Device File Alias
Creates a new file alias for a device. File aliases map device-specific file paths to media items.
**Method:** POST
**Endpoint:** /api/devices/:id/file-aliases
**Authentication:** Required (Bearer token)
**Path Parameters:**
- `id` (string, required): Device UUID
**Request Body:**
- `file_path` (string, required): Device-specific file path
- `media_item_id` (string, required): Media item UUID to link to
**Response:** Created file alias object
- `id` (string): Alias UUID
- `device_id` (string): Device UUID
- `file_path` (string): Device-specific file path
- `media_item_id` (string): Associated media item UUID
- `created_at` (string): Creation timestamp
- `updated_at` (string): Last update timestamp
**Status Codes:**
- 201: Created
- 200: Success
- 400: Invalid request body
- 401: Unauthorized
- 404: Device not found
- 500: Internal server error
code: "test_create_device_file_alias_success(status, headers, body) {\n if (status !== 201 && status !== 200) {\n throw new Error(\"Expected status 201 or 200, got \" + status);"
docs: "## Create Device File Alias\n\n Creates a new file alias for a device. File aliases map device-specific file paths to media items.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/:id/file-aliases\n\n **Authentication:** Required (Bearer token)\n\n **Path Parameters:**\n - `id` (string, required): Device UUID\n\n **Request Body:**\n - `file_path` (string, required): Device-specific file path\n - `media_item_id` (string, required): Media item UUID to link to\n\n **Response:** Created file alias object\n - `id` (string): Alias UUID\n - `device_id` (string): Device UUID\n - `file_path` (string): Device-specific file path\n - `media_item_id` (string): Associated media item UUID\n - `created_at` (string): Creation timestamp\n - `updated_at` (string): Last update timestamp\n\n **Status Codes:**\n - 201: Created\n - 200: Success\n - 400: Invalid request body\n - 401: Unauthorized\n - 404: Device not found\n - 500: Internal server error"
+31 -11
View File
@@ -2,57 +2,77 @@ info:
name: Disable Device Sync
type: http
seq: 8
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: My Kobo Clara
sync_enabled: false
auto_sync: false
sync_frequency_minutes: 30
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"sync_enabled\": false,\n \"auto_sync\": false,\n \"sync_frequency_minutes\": 30\n}"
docs: '## Disable Device Sync
docs: |-
## Disable Device Sync
Disables synchronization for a specific device.
**Method:** PUT
**Endpoint:** /api/devices/:device_id
**Authentication:** Required (Bearer token)
**Path Parameters:**
- `device_id` (string): UUID of the device
**Request Body:**
- `device_name` (string, optional): Device name
- `sync_enabled` (boolean): Must be `false`
- `auto_sync` (boolean): Should be `false`
- `sync_frequency_minutes` (integer, optional): Any value (sync disabled)
**Response:**
- `id` (string): Device UUID
- `device_name` (string): Device name
- `sync_enabled` (boolean): `false`
- `auto_sync` (boolean): `false`
- `message` (string): Confirmation message
**Status Codes:**
- 200: Sync disabled successfully
- 401: Unauthorized
- 403: Forbidden
- 404: Device not found
**Use Cases:**
- Temporarily disable sync for troubleshooting
- Stop sync for a lost or stolen device
- Disable sync before selling or giving away device
- Prevent data usage on limited connections
- Prevent data usage on limited connections'
@@ -8,32 +8,5 @@ http:
auth: none
body:
type: json
jsonBody: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\"\
: \"koreader\",\n \"device_identifier\": \"kindle-pw5-hardware-id-12345\""
docs: |-
## Initiate Device Registration
Initiates a new device registration request that requires admin approval.
**Method:** POST
**Endpoint:** /api/devices/register
**Authentication:** None (open endpoint)
**Request Body:**
- `device_name` (string, required): Human-readable device name (max 100 chars)
- `device_type` (string, required): Device type (kobo, koreader, kindle, etc.)
- `device_identifier` (string, required): Unique hardware ID (max 200 chars)
**Response:**
- `registration_id` (string): Unique registration request ID
- `status` (string): Initial status (pending)
- `expires_at` (string): Expiration timestamp (usually 24 hours)
- `message` (string): Informational message
**Status Codes:**
- 201: Registration initiated
- 400: Invalid request
- 409: Device already registered
data: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\": \"koreader\",\n \"device_identifier\": \"kindle-pw5-hardware-id-12345\""
docs: "## Initiate Device Registration\n\n Initiates a new device registration request that requires admin approval.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register\n\n **Authentication:** None (open endpoint)\n\n **Request Body:**\n - `device_name` (string, required): Human-readable device name (max 100 chars)\n - `device_type` (string, required): Device type (kobo, koreader, kindle, etc.)\n - `device_identifier` (string, required): Unique hardware ID (max 200 chars)\n\n **Response:**\n - `registration_id` (string): Unique registration request ID\n - `status` (string): Initial status (pending)\n - `expires_at` (string): Expiration timestamp (usually 24 hours)\n - `message` (string): Informational message\n\n **Status Codes:**\n - 201: Registration initiated\n - 400: Invalid request\n - 409: Device already registered"
+24 -10
View File
@@ -2,48 +2,62 @@ info:
name: Register Device
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/devices/register'
auth: none
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: My Kobo Clara
device_type: kobo
device_identifier: N1234567890123
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"device_type\": \"kobo\",\n \"device_identifier\": \"N1234567890123\"\n}"
docs: '## Register Device
docs: |-
## Register Device
Initiates device registration by sending device information to the server.
**Method:** POST
**Endpoint:** /api/devices/register
**Authentication:** None (public endpoint)
**Request Body:**
- `device_name` (string): Human-readable name for the device
- `device_type` (string): Type of device - `kobo`, `koreader`, or `web`
- `device_identifier` (string): Unique device identifier (serial number or other ID)
**Response:**
- `registration_id` (string): UUID for tracking registration status
- `status` (string): Registration status - `pending`, `approved`, or `rejected`
- `message` (string): Status message
**Status Codes:**
- 201: Registration initiated successfully
- 400: Invalid request data
- 409: Device already registered
**Notes:**
- Device registration requires user approval before activation
- Registration ID should be stored for status checking
- Device identifier must be unique per device
- Device identifier must be unique per device'
@@ -2,47 +2,60 @@ info:
name: Register KOReader Device
type: http
seq: 2
http:
method: POST
url: '{{base_url}}/api/devices/register'
auth: none
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: My Kindle Paperwhite
device_type: koreader
device_identifier: G090GP123456789
data: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\": \"koreader\",\n \"device_identifier\": \"G090GP123456789\"\n}"
docs: '## Register KOReader Device
docs: |-
## Register KOReader Device
Registers a KOReader device (typically Kindle devices running KOReader software).
**Method:** POST
**Endpoint:** /api/devices/register
**Authentication:** None (public endpoint)
**Request Body:**
- `device_name` (string): Human-readable name for the device
- `device_type` (string): Must be `koreader`
- `device_identifier` (string): Kindle serial number or unique device ID
**Response:**
- `registration_id` (string): UUID for tracking registration status
- `status` (string): Registration status - `pending`
- `message` (string): Confirmation message
**Status Codes:**
- 201: Registration initiated
- 400: Invalid device type or data
**KOReader Notes:**
- KOReader runs on Kindle, Kobo, PocketBook, and Android devices
- Device identifier is typically the device serial number
- Supports bookmarks, progress, highlights, and annotations sync
- Supports bookmarks, progress, highlights, and annotations sync'
+24 -10
View File
@@ -2,48 +2,62 @@ info:
name: Register Web Device
type: http
seq: 3
http:
method: POST
url: '{{base_url}}/api/devices/register'
auth: none
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: Chrome Browser
device_type: web
device_identifier: web-client-abc123
data: "{\n \"device_name\": \"Chrome Browser\",\n \"device_type\": \"web\",\n \"device_identifier\": \"web-client-abc123\"\n}"
docs: '## Register Web Device
docs: |-
## Register Web Device
Registers a web browser client for reading progress sync.
**Method:** POST
**Endpoint:** /api/devices/register
**Authentication:** None (public endpoint)
**Request Body:**
- `device_name` (string): Browser identification (e.g., "Chrome Browser")
- `device_type` (string): Must be `web`
- `device_identifier` (string): Unique browser/client identifier
**Response:**
- `registration_id` (string): UUID for tracking
- `status` (string): `pending` or `auto-approved`
- `message` (string): Status message
**Status Codes:**
- 201: Registration successful
- 400: Invalid request
**Web Device Notes:**
- Web devices use localStorage for device identification
- May be auto-approved without admin intervention
- Used for browser-based reading progress tracking
- Supports manual progress updates, highlights, and notes
- Supports manual progress updates, highlights, and notes'
@@ -2,60 +2,83 @@ info:
name: Update Device Settings
type: http
seq: 7
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: Updated Device Name
sync_enabled: true
auto_sync: true
sync_frequency_minutes: 10
data: "{\n \"device_name\": \"Updated Device Name\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10\n}"
docs: '## Update Device Settings
docs: |-
## Update Device Settings
Updates device configuration and sync settings.
**Method:** PUT
**Endpoint:** /api/devices/:device_id
**Authentication:** Required (Bearer token)
**Path Parameters:**
- `device_id` (string): UUID of the device
**Request Body:**
- `device_name` (string, optional): New device name
- `sync_enabled` (boolean, optional): Enable/disable sync
- `auto_sync` (boolean, optional): Enable automatic sync
- `sync_frequency_minutes` (integer, optional): Sync interval (5-1440 minutes)
**Response:**
- `id` (string): Device UUID
- `device_name` (string): Updated device name
- `sync_enabled` (boolean): Updated sync status
- `auto_sync` (boolean): Updated auto-sync setting
- `sync_frequency_minutes` (integer): Updated sync interval
- `updated_at` (string): Update timestamp
**Status Codes:**
- 200: Settings updated successfully
- 400: Invalid sync frequency or data
- 401: Unauthorized
- 403: Forbidden (device belongs to different user)
- 404: Device not found
**Sync Frequency Guidelines:**
- Mobile devices: 10-30 minutes
- E-readers on WiFi: 15-60 minutes
- Web clients: 5-15 minutes
- Minimum: 5 minutes
- Maximum: 1440 minutes (24 hours)
- Maximum: 1440 minutes (24 hours)'
+2 -32
View File
@@ -8,35 +8,5 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"device_name\": \"My Updated Kindle\",\n \"sync_enabled\"\
: true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10"
docs: |-
## Update Device
Updates device settings and synchronization preferences.
**Method:** PUT
**Endpoint:** /api/devices/{device_id}
**Authentication:** Required (Bearer token, admin or device owner)
**Path Parameters:**
- `device_id` (string): Device ID
**Request Body:**
- `device_name` (string, optional): New device name (max 100 chars)
- `sync_enabled` (boolean, optional): Enable/disable synchronization
- `auto_sync` (boolean, optional): Enable automatic synchronization
- `sync_frequency_minutes` (integer, optional): Sync frequency in minutes (5-1440)
**Response:**
- Updated device object
**Status Codes:**
- 200: Success
- 400: Invalid request
- 401: Unauthorized
- 403: Forbidden (not device owner)
- 404: Device not found
data: "{\n \"device_name\": \"My Updated Kindle\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10"
docs: "## Update Device\n\n Updates device settings and synchronization preferences.\n\n **Method:** PUT\n\n **Endpoint:** /api/devices/{device_id}\n\n **Authentication:** Required (Bearer token, admin or device owner)\n\n **Path Parameters:**\n - `device_id` (string): Device ID\n\n **Request Body:**\n - `device_name` (string, optional): New device name (max 100 chars)\n - `sync_enabled` (boolean, optional): Enable/disable synchronization\n - `auto_sync` (boolean, optional): Enable automatic synchronization\n - `sync_frequency_minutes` (integer, optional): Sync frequency in minutes (5-1440)\n\n **Response:**\n - Updated device object\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 403: Forbidden (not device owner)\n - 404: Device not found"
@@ -2,65 +2,92 @@ info:
name: Update Sync Frequency
type: http
seq: 9
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: Content-Type
value: application/json
body:
type: json
json:
device_name: My Kobo Clara
sync_enabled: true
auto_sync: true
sync_frequency_minutes: 15
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 15\n}"
docs: '## Update Sync Frequency
docs: |-
## Update Sync Frequency
Changes how often the device automatically syncs with the server.
**Method:** PUT
**Endpoint:** /api/devices/:device_id
**Authentication:** Required (Bearer token)
**Path Parameters:**
- `device_id` (string): UUID of the device
**Request Body:**
- `device_name` (string, optional): Device name
- `sync_enabled` (boolean): Must be `true` for auto-sync
- `auto_sync` (boolean): Must be `true`
- `sync_frequency_minutes` (integer): New sync interval (5-1440)
**Response:**
- `id` (string): Device UUID
- `sync_enabled` (boolean): `true`
- `auto_sync` (boolean): `true`
- `sync_frequency_minutes` (integer): Updated interval
- `next_sync_at` (string): Estimated next sync time
- `updated_at` (string): Update timestamp
**Status Codes:**
- 200: Frequency updated successfully
- 400: Invalid frequency value
- 401: Unauthorized
- 403: Forbidden
- 404: Device not found
**Recommended Frequencies:**
- **Active reading:** 5-10 minutes
- **Normal usage:** 15-30 minutes
- **Occasional reading:** 30-60 minutes
- **Battery saving:** 60+ minutes
- **WiFi only (3G):** 30-60 minutes
**Notes:**
- More frequent sync = more battery usage
- Sync only occurs when device is online
- Manual sync can be triggered anytime regardless of frequency
- Manual sync can be triggered anytime regardless of frequency'