Files
bookhoard/docs/developer/api/media-items/list_media_items.md
T
John O'Keefe 6f13dc2b63 docs(media-items core): Beam WO5 batch 4 — 12 endpoints backfilled, registry pinned
Beam backfilled list/get/create/update/delete media-item, search, ratings
CRUD, progress GET/PUT. Beam correctly identified create/update/delete as
jwt+admin (admin group in the router — verified).

Claude registry: 12 entries. Notable pins:
- get_media_item: hand-built ~44-key map pinned verbatim from the handler
- create/update return the full database.MediaItems row (74 columns) —
  examples merged up to the real shape via gate-driven merge script
- search returns []SearchMediaItemsRow (sqlc row — Real type pinned)
- rating scale is 1-10 int (odd = half-star); GET returns {rating: null} when
  absent; update reuses the create handler (201)
- progress GET: 25 base keys + 4 CONDITIONAL position-authority keys
  (css_selector/anchor_href/char_offset/context_text — added by the handler
  for convertible formats with a valid CFI); PUT progress binds
  sync.SaveProgressRequest and returns database.ReadingProgress
- Beam's examples were missing entirely on 4 files (list/search/progress
  GET/PUT) — relabeled existing fences or inserted contract-shaped blocks

Gate-driven merge scripts (object + array variants) brought all examples to
the exact handler key sets. make test 9/9.
2026-10-24 16:09:38 -04:00

4.7 KiB

method, path, auth, area
method path auth area
GET /api/media-items jwt media-items

List Media Items

Retrieve a paginated list of media items, scoped to a library or across all libraries.

Endpoint: GET /api/media-items Auth: Required

Query Parameters

Parameter Type Required Description
library_id string No Library UUID. If omitted, items from all libraries are returned
limit int No Items to return (default 50, max 1000)
offset int No Items to skip (must be >= 0)
sort string No Sort expression, default created_at DESC

Allowed sort expressions

created_at, title, author, series, date_published, copyright_year, page_count, genre — each with ASC or DESC (e.g. title ASC). Any other value silently falls back to created_at DESC.

Request Headers

Header Type Required Description
Authorization string Yes Bearer token

Example Request

GET /api/media-items?library_id=uuid&limit=20&offset=0&sort=title%20ASC
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response (200 OK)

The response body is {"data": [...]} in both modes. The item shape differs by mode.

No total is returned — page until fewer items than limit come back.

With library_id — full database rows

Nullable columns serialize as null.

{
  "data": [
    {
      "id": "uuid",
      "library_id": "uuid",
      "title": "Book Title",
      "author": "Author Name",
      "isbn": "978-...",
      "description": "Book description",
      "file_path": "relative/path/book.epub",
      "file_size": 1024000,
      "mime_type": "application/epub+zip",
      "cover_image_path": "relative/path/cover.jpg",
      "series": "Series Name",
      "series_number": 1,
      "tags": ["sci-fi"],
      "asin": null,
      "date_published": "2023-06-01",
      "publisher": null,
      "contributors": ["Author Name"],
      "language": "en",
      "edition": null,
      "page_count": 350,
      "genre": "Science Fiction",
      "copyright_year": 2023,
      "goodreads_id": null,
      "openlibrary_id": null,
      "google_books_id": null,
      "added_by_admin_id": "uuid",
      "created_at": "2026-01-31T10:00:00Z",
      "imported_at": "2026-01-31T10:00:00Z",
      "updated_at": "2026-01-31T10:00:00Z",
      "format_group": "epub",
      "format_mimetype": "application/epub+zip",
      "is_reflowable": true,
      "has_fixed_layout": false,
      "total_characters": 480000,
      "chapter_count": 24
    }
  ]
}

Note: in this mode file_path and cover_image_path are the raw relative storage paths, not URLs.

Without library_id — curated items with resolved URLs

Across all libraries; file and cover paths are resolved to fetchable URL paths (/uploads/... or library-scoped paths):

{
  "data": [
    {
      "id": "uuid",
      "library_id": "uuid",
      "title": "Book Title",
      "author": "Author Name",
      "isbn": "978-...",
      "description": "Book description",
      "file_path": "/api/libraries/<uuid>/files/...",
      "file_size": 1024000,
      "mime_type": "application/epub+zip",
      "cover_image_path": "/api/libraries/<uuid>/files/.../cover.jpg",
      "series": "Series Name",
      "series_number": 1,
      "tags": ["sci-fi"],
      "asin": null,
      "date_published": "2023-06-01",
      "publisher": null,
      "contributors": ["Author Name"],
      "language": "en",
      "edition": null,
      "page_count": 350,
      "genre": "Science Fiction",
      "created_at": "2026-01-31T10:00:00Z",
      "updated_at": "2026-01-31T10:00:00Z",
      "format_group": "epub",
      "manga_type": null,
      "reading_direction": null,
      "series_count": null,
      "volume": null,
      "imprint": null,
      "age_rating": null,
      "web_url": null,
      "metadata_notes": null,
      "community_rating": null,
      "story_arc": null,
      "is_black_and_white": false,
      "alternate_info": null,
      "scan_information": null,
      "summary": null
    }
  ]
}

Error Responses

Code Description
400 Invalid library_id, offset < 0
401 Invalid or expired token
500 Query failure (returned as {"error": …})