Files
bookhoard/docs/developer/api/media-items/update_media_item.md
T
John O'Keefe 8aa66a30fc docs(api): sync mirrors with the retired rules CRUD and the chain-order endpoint
Three mirrors had drifted:

- The rules-endpoint retirement (4f71eda6) deleted the routes but not
  their mirrors: removed docs/developer/api/collections/
  {add_auto_assign_rule,remove_auto_assign_rule,test_rule,update_rule}
  .md + their bruno twins, and pruned /api/collections/test-rules,
  /{id}/rules, /{id}/rules/{ruleId} from the generated openapi spec
  (hand-edited — regenerating with -update would wipe hand-authored
  bruno suites that predate the docs mirrors).
- New endpoint PUT /api/collections/:id/view-settings gets a doc page
  + schema-registry entry + bruno mirror (repo convention: the route
  and its docs land together).
- 54 pre-existing TestDocsMatchRoutes failures: the media-item
  endpoints emit the 16 episode/download fields (source_feed_id,
  feed_position, download_state, enclosure_url, hosts/guests, …) and
  libraries emit purpose/allow_member_feeds, but the doc examples
  were never extended — the package only runs on the host, so the
  container suite never caught it. Examples now carry every key the
  handlers emit; internal/docs is fully green.
2026-10-31 15:40:21 -04:00

4.2 KiB

method, path, auth, area
method path auth area
PUT /api/media-items/:id jwt+admin media-items

Update Media Item

Update media item metadata (Admin only).

Endpoint: PUT /api/media-items/{media_id} Auth: Required (Admin only) Content-Type: application/json

Path Parameters

Parameter Type Required Description
media_id string Yes Media item UUID

Request Body

Field Type Required Description
title string No Updated title
author string No Updated author
description string No Updated description
series string No Series name
series_number integer No Number in series
tags array of string No Updated tags (auto-normalized)
contributors array of string No Updated contributors (auto-normalized)

Tag/Contributor Normalization:

  • Tags are titlecased and deduplicated (case-insensitive)
  • Contributors preserve original casing and punctuation
  • Punctuation-preferred deduplication (keeps "ACME CORP." over "acme corp")
  • Search fields auto-generated for case-insensitive search

Example Request

{
  "title": "Updated Title",
  "author": "Updated Author",
  "description": "Updated description",
  "series": "Series",
  "series_number": 2
}

Response (200 OK)

{
  "id": "uuid",
  "title": "Updated Title",
  "author": "Updated Author",
  "description": "Updated description",
  "series": "Series",
  "series_number": 2,
  "updated_at": "2026-01-31T10:00:00Z",
  "abridged": null,
  "added_by_admin_id": null,
  "age_rating": null,
  "alternate_info": null,
  "archived_at": null,
  "asin": null,
  "audio_metadata": null,
  "authors": null,
  "authors_search": null,
  "chapter_count": null,
  "chapter_metadata": null,
  "community_rating": null,
  "contributors": null,
  "contributors_search": null,
  "copyright_year": null,
  "cover_image_path": null,
  "created_at": null,
  "date_published": null,
  "edition": null,
  "entitlement_id": null,
  "explicit": null,
  "file_path": null,
  "file_sha256": null,
  "file_size": null,
  "format_group": null,
  "format_mimetype": null,
  "genre": null,
  "goodreads_id": null,
  "google_books_id": null,
  "has_fixed_layout": null,
  "hash_confidence": null,
  "imported_at": null,
  "imprint": null,
  "is_black_and_white": null,
  "is_reflowable": null,
  "isbn": null,
  "kobo_content_id": null,
  "kobo_metadata": null,
  "language": null,
  "library_id": null,
  "library_type_name": null,
  "manga_type": null,
  "metadata_notes": null,
  "metadata_overrides": null,
  "mime_type": null,
  "missing_scan_count": null,
  "narrators": null,
  "narrators_search": null,
  "openlibrary_id": null,
  "opf_identifier": null,
  "opf_uuid": null,
  "page_count": null,
  "publisher": null,
  "publishers": null,
  "publishers_search": null,
  "reading_direction": null,
  "revision_number": null,
  "scan_information": null,
  "series_count": null,
  "story_arc": null,
  "subtitle": null,
  "summary": null,
  "tags": null,
  "tags_search": null,
  "total_characters": null,
  "volume": null,
  "web_url": null,
  "source": null,
  "source_feed_id": null,
  "feed_position": null,
  "episode_number": null,
  "season_number": null,
  "episode_guid": null,
  "enclosure_url": null,
  "chapters_url": null,
  "transcript_url": null,
  "hosts": null,
  "guests": null,
  "declared_duration_seconds": null,
  "download_state": null,
  "download_attempts": null,
  "download_queue_pos": null,
  "download_error": null
}

Error Responses

Code Description
400 Invalid input data
401 Invalid or expired token
403 User is not an admin
404 Media item not found