docs(catalogs): GET /api/catalogs/measurements contract (chat#1850)

Merged
SW
4mo ago
+150-0

What

Adds the OpenAPI contract for GET /api/catalogs/measurements?catalogId= — per-ISRC latest play counts for a catalog plus a server-derived valuation band { low, mid, high }.

Part of recoupable/chat#1850 (Valuation-first homepage / Catalog HQ) — the data plumbing deferred in chat#1801 / chat#1803. Documentation-driven: this contract merges first, then recoupable/api#757 implements it.

Contract

  • Query: catalogId (uuid, required). The catalog must belong to the authenticated account (resolved from credentials — Privy bearer or x-api-key — never from input).
  • 200: { status, measurements[], valuation, total_streams, catalog_age_years }
    • measurements[] — newest capture per ISRC: { isrc, title, playcount, measured_at }; never-measured songs omitted.
    • valuation — { low, mid, high } USD, derived at read time (not persisted, per the chat#1850 architecture decision) using the same model as the marketing valuation card (marketing/lib/valuation/computeCatalogValuation.ts): annual run-rate = lifetime streams ÷ catalog age (lifetime-average proxy; earliest Spotify release date, min 1y, default 5y when unknown) → NLS ($0.0035/stream × 1.25/1.4/1.6 all-DSP gross-up × 0.85 post-distribution × 0.75 post-royalty) → 10x/13x/16x master-catalog multiple.
  • Errors (only ones the implementation emits): 400 missing/invalid catalogId · 401 unauthed · 404 catalog unknown or owned by another account.

Changes

  • api-reference/openapi/releases.json — new path + 3 schemas (CatalogMeasurementsResponse, CatalogTrackMeasurement, ValuationBand), purely additive (surgical insertion, no re-dump; every pre-existing path/schema byte-identical, verified programmatically); JSON re-validated as parseable.
  • api-reference/songs/catalog-measurements.mdx — frontmatter-only reference page (docs#243 pattern).
  • docs.json — nav entry in the Catalogs group.

Merge order

  1. This PR (docs, base main) — the contract.
  2. recoupable/api#757 — the implementation (base main; the api test-branch PR flow was retired in api#750).

🤖 Generated with Claude Code


Summary by cubic

Adds the OpenAPI contract for GET /api/catalogs/measurements to return latest per-ISRC play counts and a server-derived valuation band. This unblocks the Catalog HQ valuation work in chat#1850; API implementation will follow.

  • New Features
    • New path GET /api/catalogs/measurements?catalogId= in api-reference/openapi/releases.json with schemas: CatalogMeasurementsResponse, CatalogTrackMeasurement, ValuationBand.
    • Response includes measurements[] (newest per ISRC), valuation { low, mid, high }, total_streams, catalog_age_years; errors: 400/401/404.
    • Valuation band is computed at read time and mirrors the marketing valuation model (no persistence).
    • Added api-reference/songs/catalog-measurements.mdx and nav entry in docs.json; changes are additive only.