-
Notifications
You must be signed in to change notification settings - Fork 4
docs(catalogs): GET /api/catalogs/{catalogId}/valuations — persisted valuation history (chat#1889 row 15) #279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1414,7 +1414,7 @@ | |||||||||||||||||||
| "/api/valuation": { | ||||||||||||||||||||
| "post": { | ||||||||||||||||||||
| "summary": "Run valuation", | ||||||||||||||||||||
| "description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes an account-owned catalog from the resulting snapshot (idempotent - see [Create catalog](/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. The owning account is taken from the credentials, never the body. The searched artist is also linked to the caller's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes).", | ||||||||||||||||||||
| "description": "Generate a catalog from a Spotify artist in one call. Resolves the artist's releases, captures current Spotify play counts (spending the account's credits), materializes an account-owned catalog from the resulting snapshot (idempotent - see [Create catalog](/api-reference/songs/catalogs-create)), and returns the catalog with its estimated value band. The owning account is taken from the credentials, never the body. The searched artist is also linked to the caller's roster (so a funnel signup lands with a populated `GET /api/artists` it can confirm); when the catalog's songs already resolve a canonical artist that one is used, otherwise the searched Spotify artist is linked directly. Synchronous: the request waits for the capture to land (typically under two minutes). Each run also persists a row in the catalog's valuation history, readable via [Get Catalog Valuations](/api-reference/songs/catalog-valuations).", | ||||||||||||||||||||
| "security": [ | ||||||||||||||||||||
| { | ||||||||||||||||||||
| "apiKeyAuth": [] | ||||||||||||||||||||
|
|
@@ -1649,6 +1649,85 @@ | |||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "/api/catalogs/{catalogId}/valuations": { | ||||||||||||||||||||
| "get": { | ||||||||||||||||||||
| "description": "Get the persisted valuation history for a catalog, latest first. A row is written each time a valuation band is computed for the whole catalog (valuation runs and measurement reads persist at most one row per catalog per day). Use limit=1 for the current value. History is what makes week-over-week deltas possible.", | ||||||||||||||||||||
| "security": [ | ||||||||||||||||||||
| { | ||||||||||||||||||||
| "apiKeyAuth": [] | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| { | ||||||||||||||||||||
| "bearerAuth": [] | ||||||||||||||||||||
| } | ||||||||||||||||||||
| ], | ||||||||||||||||||||
| "parameters": [ | ||||||||||||||||||||
| { | ||||||||||||||||||||
| "name": "catalogId", | ||||||||||||||||||||
| "in": "path", | ||||||||||||||||||||
| "description": "The unique identifier of the catalog. The catalog must belong to the authenticated account. Malformed (non-uuid) values are rejected with 400.", | ||||||||||||||||||||
| "required": true, | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "type": "string", | ||||||||||||||||||||
| "format": "uuid" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| { | ||||||||||||||||||||
| "name": "limit", | ||||||||||||||||||||
| "in": "query", | ||||||||||||||||||||
| "description": "Maximum number of valuation rows to return, latest first (default 30, max 100). limit=1 returns the current value. Invalid values are rejected with 400.", | ||||||||||||||||||||
| "required": false, | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "type": "integer", | ||||||||||||||||||||
| "minimum": 1, | ||||||||||||||||||||
| "maximum": 100, | ||||||||||||||||||||
| "default": 30 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| ], | ||||||||||||||||||||
| "responses": { | ||||||||||||||||||||
| "200": { | ||||||||||||||||||||
| "description": "The catalog's persisted valuation rows, latest first. Empty when no valuation has been persisted yet.", | ||||||||||||||||||||
| "content": { | ||||||||||||||||||||
| "application/json": { | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "$ref": "#/components/schemas/CatalogValuationsResponse" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "400": { | ||||||||||||||||||||
| "description": "Malformed catalogId or limit", | ||||||||||||||||||||
| "content": { | ||||||||||||||||||||
| "application/json": { | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "$ref": "#/components/schemas/Error" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "401": { | ||||||||||||||||||||
| "description": "Missing or invalid credentials", | ||||||||||||||||||||
| "content": { | ||||||||||||||||||||
| "application/json": { | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "$ref": "#/components/schemas/Error" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "404": { | ||||||||||||||||||||
| "description": "Catalog not found or not owned by the authenticated account", | ||||||||||||||||||||
| "content": { | ||||||||||||||||||||
| "application/json": { | ||||||||||||||||||||
| "schema": { | ||||||||||||||||||||
| "$ref": "#/components/schemas/Error" | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "/api/catalogs/{catalogId}/measurements": { | ||||||||||||||||||||
| "get": { | ||||||||||||||||||||
| "description": "Get the latest play counts and a derived valuation band for a catalog. Measurements are captured by [Create measurement job](/api-reference/research/measurement-jobs) runs; the band is computed at read time from the latest capture per song.", | ||||||||||||||||||||
|
|
@@ -2821,6 +2900,61 @@ | |||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "CatalogValuationsResponse": { | ||||||||||||||||||||
| "type": "object", | ||||||||||||||||||||
| "required": [ | ||||||||||||||||||||
| "status", | ||||||||||||||||||||
| "valuations" | ||||||||||||||||||||
| ], | ||||||||||||||||||||
| "properties": { | ||||||||||||||||||||
| "status": { | ||||||||||||||||||||
| "type": "string", | ||||||||||||||||||||
| "example": "success" | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The Prompt for AI agents |
||||||||||||||||||||
| }, | ||||||||||||||||||||
|
Comment on lines
+2910
to
+2913
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win Constrain successful response status to The example implies Proposed fix "status": {
"type": "string",
+ "enum": ["success"],
"example": "success"
},📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| "valuations": { | ||||||||||||||||||||
| "type": "array", | ||||||||||||||||||||
| "description": "Persisted valuation rows, latest first.", | ||||||||||||||||||||
| "items": { | ||||||||||||||||||||
| "type": "object", | ||||||||||||||||||||
| "required": [ | ||||||||||||||||||||
| "low", | ||||||||||||||||||||
| "mid", | ||||||||||||||||||||
| "high", | ||||||||||||||||||||
| "measured_song_count", | ||||||||||||||||||||
| "total_streams", | ||||||||||||||||||||
| "measured_at" | ||||||||||||||||||||
| ], | ||||||||||||||||||||
| "properties": { | ||||||||||||||||||||
| "low": { | ||||||||||||||||||||
| "type": "number", | ||||||||||||||||||||
| "description": "Low end of the estimated catalog value band, USD." | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "mid": { | ||||||||||||||||||||
| "type": "number", | ||||||||||||||||||||
| "description": "Midpoint of the estimated catalog value band, USD." | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "high": { | ||||||||||||||||||||
| "type": "number", | ||||||||||||||||||||
| "description": "High end of the estimated catalog value band, USD." | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "measured_song_count": { | ||||||||||||||||||||
| "type": "integer", | ||||||||||||||||||||
| "description": "Songs measured in the capture this valuation was computed from." | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "total_streams": { | ||||||||||||||||||||
| "type": "integer", | ||||||||||||||||||||
| "description": "Whole-catalog lifetime stream total at measurement time." | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "measured_at": { | ||||||||||||||||||||
| "type": "string", | ||||||||||||||||||||
| "format": "date-time", | ||||||||||||||||||||
| "description": "When the underlying measurement was taken." | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| "CreateArtistRequest": { | ||||||||||||||||||||
| "type": "object", | ||||||||||||||||||||
| "required": [ | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| title: Get Catalog Valuations | ||
| openapi: get /api/catalogs/{catalogId}/valuations | ||
| --- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reconcile per-run persistence with daily deduplication.
These descriptions say each run writes a row, but also say there is at most one row per catalog per day. Clarify whether the daily row is coalesced or replaced so clients can reason correctly about history length and week-over-week comparisons.
Also applies to: 1654-1654
🤖 Prompt for AI Agents