series
Resolved series catalog
📄️ List series ordered by last release timestamp (most recent first by default).
List series ordered by last release timestamp (most recent first by default).
📄️ Create a manual series: a provider-less catalog entry for a real series the active provider lacks. The operator then links releases to it via `POST /releases/{id}/link` with `{ 'seriesId': N }`.
No `series_external_ids` row is created, so this series never
📄️ Export the (filtered) series catalog as a downloadable file.
Export the (filtered) series catalog as a downloadable file.
📄️ Incremental release feed: series with coverage activity, ordered by `(updatedAt, id)` after an opaque cursor. A consumer (e.g. a Codex release plugin) polls this a few times a day, stores `nextCursor`, and only ever receives series whose coverage changed since its last poll. Keyset, not offset, so it's gap-free and dupe-free while series are re-stamped concurrently; delivery is at-least-once, so consumers upsert by `seriesId`.
Incremental release feed: series with coverage activity, ordered by
📄️ Filtered variant of [`feed`]: same cursor walk, but narrowed to the series whose provider ids the consumer sends in the body. Use this (over the `GET`) when a consumer tracks a known subset — a Codex release plugin posting the `provider:externalId` set it owns so it only receives changes it cares about. It's a `POST` purely so the id list can be large; it mutates nothing and is gated like the other reads.
Filtered variant of [`feed`]: same cursor walk, but narrowed to the series
📄️ Add a series straight from a metadata provider, for series with no discovered release yet. Reuses the resolver's `upsert_series_from_metadata` (the same path the review link-by-provider flow uses), so the row is provider-backed and carries its `series_external_ids` mapping — future discovered releases auto-resolve to it. Idempotent on `(provider, externalId)`: an existing mapping returns `200` with the existing row; a fresh fetch returns `201`. When `wishlist` is set (the default) the series is clipped to the wishlist.
Add a series straight from a metadata provider, for series with no
📄️ Clear `metadata_hash` for every provider-backed series row in scope so the next refresh tick rewrites them. The persist layer short-circuits the series UPDATE when the incoming provider payload hashes to the stored value; that's the right call for steady-state refreshes, but it strands existing rows whenever a new denormalized column lands on the `series` table (the upstream payload is unchanged → hash matches → write skipped → new column stays NULL forever).
This endpoint is the operator escape hatch for that scenario. It runs
📄️ Recompute every release's volume/chapter span and every series' `highest_volume` / `highest_chapter` mark from the stored file lists (titles as fallback). Network-free and idempotent. Unlike the incremental bump that runs when a release is linked, this is an authoritative pass: a series' marks are *replaced* with the MAX across its currently-linked releases, so it also corrects values an earlier, more eager parser over-counted and clears marks on series whose releases no longer parse to anything.
Use it after changing the span-parsing logic, or to backfill a catalog
📄️ Trigger a bulk refresh of stale series rows against the active metadata provider.
Default (`all=false`): one settings-bounded tick. It reads `batch_size`
📄️ Series detail, including the resolved external-ID mappings.
Series detail, including the resolved external-ID mappings.
📄️ Edit a manual series' descriptive fields. **Manual rows only**: a provider-backed series (`metadataSource` ≠ `manual`) is owned by the provider and would have any edit overwritten on the next metadata refresh, so it is rejected with `409`. Provider/metadata/provenance columns are never touched — only the operator-authored descriptive fields change.
Edit a manual series' descriptive fields. **Manual rows only**: a
📄️ Toggle a series' `ignore_completion` flag. When set, the series' Codex status is forced to `ignored` so the perpetually-false 'Behind' signal is muted — meant for series read in omnibus, where source single-volume numbering is permanently ahead of the owned omnibus numbering.
Unlike the manual-edit `PATCH`, this works on **any** series (provider-backed
📄️ Re-fetch metadata for a series from the active provider and re-persist.
Re-fetch metadata for a series from the active provider and re-persist.
📄️ Clip or un-clip a series from the operator's wishlist — a curated 'download later' list. Works on **any** series (provider-backed or manual): the flag is operator-owned and a metadata refresh never touches it. Independent of Codex ownership; clipping a series the operator already owns is allowed and import never auto-clears it (removal is manual).
Clip or un-clip a series from the operator's wishlist — a curated 'download