docs(research): reconcile playcount contract with live api behavior
Merged
SW
4mo ago+119+119+012345678901234567890123456789-14-14-01234567890123456789
What
The reconcile step for the playcount family — every divergence found while live-verifying recoupable/api#657 and recoupable/api#660 (results tables on those PRs), fixed on the docs side. The live response is ground truth.
track-stats
- Description now states the sourcing model: Spotify served Apify-first from the measurement store (TTL-refreshed platform-displayed counts), Songstats for other sources, upstream status passthrough (e.g. 429 on quota exhaustion — observed live).
captured_atscoped: present only on store-served entries.- Store-served entries'
datacarries onlystreams_total(platform-displayed count caveat referenced). - Minimal
{ result, stats }envelope documented for fully-store-served responses.
track-historic-stats
- Store-only Spotify history (snapshot + backfilled points, per-point
data_source), the partial-response + backfill-enqueue behavior, and the minimal envelope.
playcounts (the real catch)
- Nullability was inverted: docs had
isrcnullable andspotify_track_idrequired; the implementation never emits a nullisrc(mapped tracks only) but can emit a nullspotify_track_id. Swapped. album.label/album.copyrighthonestly marked always null until snapshots persist album metadata;album.namesourced from the song record, not the platform page.- Mapped-tracks-only coverage stated.
All four playcount-family endpoints
- 402 documented with the real body (
insufficient_credits,remaining_credits,required_credits,checkoutUrl— shape read frombuildInsufficientCreditsResponse), via a newResearchInsufficientCreditsResponseschema.
Verification
Additive-leaning diff (84+/13−, the deletions are replaced descriptions); mint validation passes. track-playcount-deltas needed no changes — it matched the contract exactly.
Closes the docs-reconciliation follow-up noted on recoupable/chat#1791.
🤖 Generated with Claude Code
Summary by cubic
Reconciled research playcount docs with live API behavior. Tightened field contracts, moved sourcing details into response schemas, and added explicit 402 across endpoints plus 429 passthrough on stats endpoints.
-
Bug Fixes
- playcounts:
isrcrequired;spotify_track_idnullable. Album name/label/copyright clarified; mapped-tracks only. - Sourcing/envelopes:
captured_atonly for store-served; store-served data onlystreams_total; minimal{ result, stats }when fully store-served; Spotify history from store with per-pointdata_sourceand enqueue backfill. - Declared
429passthrough (ResearchErrorResponse) ontrack-statsandtrack-historic-stats. - OpenAPI 3.1 nullability: use
type: [string, null]forspotify_track_idand album fields.
- playcounts:
-
New Features
- Added
402Insufficient Credits to all playcount endpoints withResearchInsufficientCreditsResponse;error,remaining_credits,required_credits,checkoutUrlrequired;declineReasonoptional.
- Added
Summary by CodeRabbit
- Documentation
- Updated API documentation for track stats and playcount endpoints to document insufficient research credits responses and checkout URLs for purchasing additional credits.
- Improved field descriptions to clarify data availability based on data source and enhanced endpoint behavior documentation including provider routing and refresh mechanics.