# Collections API Documentation Complete API reference for collection management endpoints. **Base Path**: `/api/collections` --- ## Overview Collections allow you to organize your books into custom categories with: - **Auto-assignment rules**: Automatically add books matching criteria - **View settings**: Per-device display preferences - **Shelf mappings**: Sync to device-specific shelves (Kobo, KOReader) --- ## Endpoints ### List All Collections **Endpoint**: `GET /api/collections` **Authentication**: Required **Description**: Get all collections for the authenticated user **Response** (200 OK): ```json { "collections": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Science Fiction", "description": "My sci-fi collection", "color": "#FF5733", "icon": "🚀", "auto_assign_rules": [ { "field": "genre", "operator": "equals", "value": "Science Fiction", "priority": 1, "enabled": true } ], "view_settings": { "kobo": { "view_mode": "grid", "sort_order": "name", "items_per_page": 24 } }, "created_at": "2026-02-01T10:00:00Z" } ], "total": 1 } ``` ### Create Collection **Endpoint**: `POST /api/collections` **Authentication**: Required **Description**: Create a new collection **Request Body**: ```json { "name": "To Read", "description": "Books I want to read soon", "color": "#00FF00", "icon": "📖", "auto_assign_rules": [ { "field": "tags", "operator": "contains", "value": "to-read", "priority": 1, "enabled": true } ], "view_settings": { "kobo": { "view_mode": "grid" }, "koreader": { "view_mode": "list" } } } ``` **Fields**: - `name` (required): Collection name (max 255 chars) - `description` (optional): Collection description - `color` (optional): Hex color code (e.g., "#FF5733") - `icon` (optional): Emoji icon (e.g., "🚀", "📖") - `auto_assign_rules` (optional): Array of rule objects - `view_settings` (optional): Per-device display preferences **Rule Object**: - `field`: Field to match on (genre, author, series, language, publisher, copyright_year, tags) - `operator`: Comparison operator (equals, not_equals, contains, not_contains, starts_with, ends_with, greater_than, less_than) - `value`: Value to compare against - `priority`: Rule priority (1 = highest) - `enabled`: Whether rule is active **Response** (201 Created): Collection object ### Get Collection Details **Endpoint**: `GET /api/collections/{id}` **Authentication**: Required **Description**: Get single collection with all books **Path Parameters**: - `id`: Collection UUID **Response** (200 OK): ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Science Fiction", "description": "My sci-fi collection", "color": "#FF5733", "icon": "🚀", "books": [ { "media_item_id": "660e8400-e29b-41d4-a716-446655440000", "title": "Foundation", "author": "Isaac Asimov", "cover_image_path": "/covers/foundation.jpg" } ], "auto_assign_rules": [], "view_settings": {}, "created_at": "2026-02-01T10:00:00Z" } ``` ### Update Collection **Endpoint**: `PUT /api/collections/{id}` **Authentication**: Required **Description**: Update collection details **Path Parameters**: - `id`: Collection UUID **Request Body**: All fields are optional ```json { "name": "Sci-Fi Favorites", "description": "Updated description", "color": "#BLUE", "icon": "🌟" } ``` **Response** (200 OK): Updated collection object ### Delete Collection **Endpoint**: `DELETE /api/collections/{id}` **Authentication**: Required **Description**: Delete a collection (books are NOT deleted) **Path Parameters**: - `id`: Collection UUID **Response** (204 No Content) --- ## Collection Books ### Add Books to Collection **Endpoint**: `POST /api/collections/{id}/books` **Authentication**: Required **Description**: Add one or more books to a collection **Path Parameters**: - `id`: Collection UUID **Request Body**: ```json { "book_ids": [ "660e8400-e29b-41d4-a716-446655440000", "770e8400-e29b-41d4-a716-446655440000", "880e8400-e29b-41d4-a716-446655440000" ] } ``` **Response** (204 No Content) ### Remove Book from Collection **Endpoint**: `DELETE /api/collections/{id}/books/{bookId}` **Authentication**: Required **Description**: Remove a single book from a collection **Path Parameters**: - `id`: Collection UUID - `bookId`: Media Item UUID **Response** (204 No Content) ### Bulk Remove Books **Endpoint**: `POST /api/collections/{id}/books/bulk-remove` **Authentication**: Required **Description**: Remove multiple books at once (efficient) **Path Parameters**: - `id`: Collection UUID **Request Body**: ```json { "book_ids": [ "660e8400-e29b-41d4-a716-446655440000", "770e8400-e29b-41d4-a716-446655440000" ] } ``` **Response** (200 OK): ```json { "removed": 2, "total": 2 } ``` **Example**: Removing 2 books, both successfully removed ### Get Collection Books **Endpoint**: `GET /api/collections/{id}/books` **Authentication**: Required **Description**: Get all books in a collection **Path Parameters**: - `id`: Collection UUID **Query Parameters**: - `limit` (optional): Number of books to return (default: 50) - `offset` (optional): Number of books to skip (default: 0) **Response** (200 OK): ```json { "books": [ { "media_item_id": "660e8400-e29b-41d4-a716-446655440000", "title": "Foundation", "author": "Isaac Asimov", "cover_image_path": "/covers/foundation.jpg", "added_at": "2026-02-01T10:00:00Z" } ], "total": 1 } ``` --- ## Collection Rules ### Test Collection Rules **Endpoint**: `POST /api/collections/test-rules` **Authentication**: Required **Description**: Test which books would match given rules (without saving) **Request Body**: ```json { "rules": [ { "field": "genre", "operator": "equals", "value": "Science Fiction" }, { "field": "author", "operator": "contains", "value": "Asimov" } ] } ``` **Supported Fields**: - `genre`: Book genre - `author`: Book author - `series`: Book series name - `language`: Book language - `publisher`: Publisher name - `copyright_year`: Publication year (numeric comparison) - `tags`: Book tags **Supported Operators**: - `equals`: Exact match - `not_equals`: Not equal - `contains`: Contains substring (case-insensitive) - `not_contains`: Does not contain - `starts_with`: Starts with (case-insensitive) - `ends_with`: Ends with (case-insensitive) - `greater_than`: Greater than (numeric) - `less_than`: Less than (numeric) **Response** (200 OK): ```json { "matches": [ { "media_item_id": "660e8400-e29b-41d4-a716-446655440000", "title": "Foundation", "author": "Isaac Asimov", "cover_image_path": "/covers/foundation.jpg", "match_reason": "Matched rule: genre equals Science Fiction" } ], "total": 42 } ``` **Use Case**: Test rules before creating collection to verify correct book matching --- ## Device Shelf Mappings ### Get Device Shelf Mappings **Endpoint**: `GET /api/devices/{deviceId}/collections` **Authentication**: Required **Description**: Get all collection-to-shelf mappings for a device **Path Parameters**: - `deviceId`: Device UUID **Response** (200 OK): ```json { "mappings": [ { "id": "990e8400-e29b-41d4-a716-446655440000", "collection_id": "550e8400-e29b-41d4-a716-446655440000", "collection_name": "Science Fiction", "device_shelf_name": "Sci-Fi", "sync_direction": "bidirectional", "created_at": "2026-02-01T10:00:00Z" } ] } ``` ### Create Shelf Mapping **Endpoint**: `POST /api/devices/{deviceId}/collections` **Authentication**: Required **Description**: Map a collection to a device shelf **Path Parameters**: - `deviceId`: Device UUID **Request Body**: ```json { "collection_id": "550e8400-e29b-41d4-a716-446655440000", "device_shelf_name": "Sci-Fi", "sync_direction": "bidirectional" } ``` **Sync Directions**: - `bidirectional`: Sync both ways between Bookhoard and device - `book_to_hoard`: Bookhoard → Device only - `device_to_hoard`: Device → Bookhoard only - `none`: No sync (mapping only) **Response** (201 Created): Mapping object ### Update Shelf Mapping **Endpoint**: `PUT /api/devices/{deviceId}/collections/{collectionId}` **Authentication**: Required **Description**: Update existing shelf mapping **Path Parameters**: - `deviceId`: Device UUID - `collectionId`: Collection UUID **Request Body**: ```json { "device_shelf_name": "Science Fiction", "sync_direction": "book_to_hoard" } ``` **Response** (200 OK): Updated mapping object ### Delete Shelf Mapping **Endpoint**: `DELETE /api/devices/{deviceId}/collections/{collectionId}` **Authentication**: Required **Description**: Remove shelf mapping **Path Parameters**: - `deviceId`: Device UUID - `collectionId`: Collection UUID **Response** (204 No Content) --- ## Error Responses All endpoints may return these errors: **400 Bad Request**: ```json { "error": "invalid request: validation failed" } ``` **401 Unauthorized**: ```json { "error": "authentication required" } ``` **404 Not Found**: ```json { "error": "collection not found" } ``` **500 Internal Server Error**: ```json { "error": "internal server error" } ``` --- ## Rate Limiting - **Authenticated**: 100 requests per minute - **Unauthenticated**: 10 requests per minute Headers included: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1643723400 ``` --- ## Bruno OpenCollection YAML Tests Complete API tests available in `bruno/collections/`: - `Get Collections.yml` - `Create Collection.yml` - `Get Collection.yml` - `Update Collection.yml` - `Delete Collection.yml` - `Add Books to Collection.yml` - `Remove Book from Collection.yml` - `Get Book Collections.yml` - `Test Collection Rules.yml` - `Bulk Remove Books.yml` Run tests: ```bash bruno run bruno/collections/ ``` --- **Last Updated**: 2026-02-01 **Version**: 1.0