From 351b2916f6a13a6f068627c63b43ad51609d9f2a Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 11:43:44 -0500 Subject: [PATCH 1/7] docs: /research/track becomes pure id-proxy; /research/playlist clarified Follow-up to recoupable/docs#138. The api PR (recoupable/api#366) is being simplified to strictly one-upstream-call-per-endpoint so credit charges are predictable and ambiguity never gets silently swallowed by composite resolution. /research/track - Drop q and artist query params; require numeric `id` instead. - Description reframes the endpoint as a thin /track/:id proxy and points callers at GET /api/research?type=tracks&beta=true for discovery. - 400 now refers to id validation, 404 refers to unknown Chartmetric id. /research/playlist - No schema change (still takes platform + id), but the description now explicitly names this a /playlist/:platform/:id proxy and points callers at GET /api/research for name-based discovery. - id description calls out that format varies by platform. Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index c1a327d..b90f429 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -1883,7 +1883,7 @@ }, "/api/research/playlist": { "get": { - "description": "Get playlist metadata — name, description, follower count, track count, and curator info.", + "description": "Get playlist metadata — name, description, follower count, track count, and curator info.\n\nThin proxy over Chartmetric's `/playlist/:platform/:id` detail lookup. Discovery by name is the caller's job via `GET /api/research?q=&type=playlists&beta=true`.", "parameters": [ { "name": "platform", @@ -1905,7 +1905,7 @@ "name": "id", "in": "query", "required": true, - "description": "Playlist ID on the platform.", + "description": "Platform-native playlist ID. Format varies by platform — Spotify base62 (e.g. `37i9dQZF1DXcBWIGoYBM5M`), Apple/Deezer numeric, Amazon ASIN-style.", "schema": { "type": "string" } @@ -2351,24 +2351,17 @@ }, "/api/research/track": { "get": { - "description": "Get track metadata — title, artist, album, release date, popularity, and platform IDs.\n\nResolves `q` against Chartmetric's track search and returns details for the top-ranked match. Common track names are ambiguous (e.g. \"Flowers\", \"God's Plan\") — for reliable disambiguation, either pass a Spotify track URL as `q`, or pair `q` with the `artist` query param.", + "description": "Get full Chartmetric track metadata by numeric track `id` — title, artists, albums, release date, genres, popularity, and platform IDs.\n\nThis endpoint is a thin proxy over Chartmetric's `/track/:id` detail lookup. Discovery by name is the caller's job: use `GET /api/research?q=&type=tracks&beta=true` to search, pick a result's `id`, then call this endpoint. Keeping the two concerns separate means predictable credit charging and no silent wrong-match behavior for ambiguous queries.", "parameters": [ { - "name": "q", + "name": "id", "in": "query", "required": true, - "description": "Track name or Spotify track URL. URLs (e.g. `https://open.spotify.com/track/`) resolve directly without ambiguity. Plain names are searched via Chartmetric's track search; results may not match user intent without an `artist` filter.", + "description": "Chartmetric track ID (positive integer). Obtain via `GET /api/research?type=tracks&beta=true` — beta-ranked search results include the `id` field directly.", "schema": { - "type": "string" - } - }, - { - "name": "artist", - "in": "query", - "required": false, - "description": "Optional artist name used to disambiguate when `q` is a plain track name. Matched case-insensitively against the candidate tracks' artist names; the top-ranked candidate whose artist names contain this value wins. Recommended whenever `q` is not a Spotify URL.", - "schema": { - "type": "string" + "type": "string", + "pattern": "^[1-9][0-9]*$", + "example": "15194376" } } ], @@ -2384,7 +2377,7 @@ } }, "400": { - "description": "Validation error", + "description": "Validation error — `id` missing or not a positive integer", "content": { "application/json": { "schema": { @@ -2404,7 +2397,7 @@ } }, "404": { - "description": "No track matched the supplied `q` (and `artist`, when present)", + "description": "No Chartmetric track exists with the supplied `id`", "content": { "application/json": { "schema": { From 4c529481ad1a2524cdde3ce557297776d8318c49 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 11:47:46 -0500 Subject: [PATCH 2/7] docs: clarify /research/playlist id is Chartmetric numeric, not native MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified against preview of recoupable/api#366: GET /playlist?platform=spotify&id=37i9dQZF1DXcBWIGoYBM5M → 400 GET /playlist?platform=spotify&id=848051 → 200 RapCaviar Chartmetric's /playlist/:platform/:id accepts Chartmetric's own numeric playlist IDs, not the streaming platform's native IDs. Search results already expose the correct `id` field, so the workflow is: search via /api/research, feed `id` into /research/playlist. - Param description now explicitly calls out "not the native ID" - Added pattern ^[1-9][0-9]*$ + example 848051 - Endpoint description leads with "Chartmetric's own numeric playlist ID" Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index b90f429..243a8af 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -1883,7 +1883,7 @@ }, "/api/research/playlist": { "get": { - "description": "Get playlist metadata — name, description, follower count, track count, and curator info.\n\nThin proxy over Chartmetric's `/playlist/:platform/:id` detail lookup. Discovery by name is the caller's job via `GET /api/research?q=&type=playlists&beta=true`.", + "description": "Get playlist metadata — name, description, follower count, track count, and curator info.\n\nThin proxy over Chartmetric's `/playlist/:platform/:id` detail lookup. **`id` is Chartmetric's own numeric playlist ID, not the streaming-platform's native ID.** Discovery is the caller's job via `GET /api/research?q=&type=playlists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", "parameters": [ { "name": "platform", @@ -1899,15 +1899,17 @@ "youtube" ] }, - "description": "Streaming platform." + "description": "Streaming platform the Chartmetric playlist is sourced from." }, { "name": "id", "in": "query", "required": true, - "description": "Platform-native playlist ID. Format varies by platform — Spotify base62 (e.g. `37i9dQZF1DXcBWIGoYBM5M`), Apple/Deezer numeric, Amazon ASIN-style.", + "description": "Chartmetric playlist ID (positive integer). This is **not** the streaming platform's native ID — e.g. Spotify's base62 ID `37i9dQZF1DXcBWIGoYBM5M` for RapCaviar maps to Chartmetric ID `848051`. Obtain via `GET /api/research?type=playlists&beta=true`.", "schema": { - "type": "string" + "type": "string", + "pattern": "^[1-9][0-9]*$", + "example": "848051" } } ], From 8e79698cb5508b9454d6a11208b8e3895b00443c Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 12:00:06 -0500 Subject: [PATCH 3/7] docs: /research/albums becomes pure artist_id-proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the api change in recoupable/api#366 (cb6152b2). The handler no longer does a composite name→artist_id→discography resolve (which was returning wrong data for artist=Drake and artist=Taylor Swift on the preview), so the spec is updated: - Param renamed `artist` → `artist_id` - Typed as positive-integer string (pattern ^[1-9][0-9]*$), example 3380 - Description points callers at GET /api/research?type=artists&beta=true for discovery - 400 description specific to the new validation No change needed for /research/charts — the spec already enumerates `type` to {regional, viral}, `interval` to {daily, weekly}; the api change tightens the validator to actually enforce those at our layer (turning opaque upstream 400s into specific ones). Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index 243a8af..d077e84 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -880,15 +880,17 @@ }, "/api/research/albums": { "get": { - "description": "Get an artist's full discography — albums, EPs, and singles with release dates.", + "description": "Get the album discography — albums, EPs, and singles with release dates — for a Chartmetric `artist_id`.\n\nThin proxy over Chartmetric's `/artist/:id/albums`. Discovery by name is the caller's job via `GET /api/research?q=&type=artists&beta=true`. This endpoint does not resolve artist names itself.", "parameters": [ { - "name": "artist", + "name": "artist_id", "in": "query", "required": true, - "description": "Artist name or Recoup artist ID (UUID).", + "description": "Chartmetric artist ID (positive integer). Obtain via `GET /api/research?type=artists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", "schema": { - "type": "string" + "type": "string", + "pattern": "^[1-9][0-9]*$", + "example": "3380" } } ], @@ -904,7 +906,7 @@ } }, "400": { - "description": "Validation error (e.g., missing `artist` parameter)", + "description": "Validation error — `artist_id` missing or not a positive integer", "content": { "application/json": { "schema": { From a6f7e05bd63296da8986f611fd077510c2baf471 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 14:34:06 -0500 Subject: [PATCH 4/7] docs: /research/albums adds is_primary, limit, offset params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors api change in recoupable/api#366 (969f5f8a). The api now sends isPrimary=true by default to Chartmetric so /artist/:id/albums returns the artist's own discography (not features, soundtracks, DJ mixes). Spec additions: - `is_primary` (default "true") — opt into features with "false" - `limit` (positive integer) — pagination page size - `offset` (non-negative integer) — pagination offset Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index d077e84..6859a61 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -880,7 +880,7 @@ }, "/api/research/albums": { "get": { - "description": "Get the album discography — albums, EPs, and singles with release dates — for a Chartmetric `artist_id`.\n\nThin proxy over Chartmetric's `/artist/:id/albums`. Discovery by name is the caller's job via `GET /api/research?q=&type=artists&beta=true`. This endpoint does not resolve artist names itself.", + "description": "Get the album discography — albums, EPs, and singles with release dates — for a Chartmetric `artist_id`.\n\nThin proxy over Chartmetric's `/artist/:id/albums`. By default `is_primary=true`, so only albums where the artist is a main artist are returned — DJ compilations, soundtracks, and pure feature appearances are excluded. Pass `is_primary=false` to include them. Discovery by name is the caller's job via `GET /api/research?q=&type=artists&beta=true`.", "parameters": [ { "name": "artist_id", @@ -892,6 +892,37 @@ "pattern": "^[1-9][0-9]*$", "example": "3380" } + }, + { + "name": "is_primary", + "in": "query", + "required": false, + "description": "When `true` (default), returns only albums where the artist is a main artist. Set to `false` to include feature appearances, DJ compilations, and soundtracks.", + "schema": { + "type": "string", + "enum": ["true", "false"], + "default": "true" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "Number of albums to return. Defaults to Chartmetric's default (100) when omitted.", + "schema": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + } + }, + { + "name": "offset", + "in": "query", + "required": false, + "description": "Pagination offset. Defaults to 0 when omitted.", + "schema": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } } ], "responses": { From a7e01743663f540102f49f1db66465ebb7724395 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 14:37:26 -0500 Subject: [PATCH 5/7] docs: /api/research gains beta/platforms/offset + realistic result schema Mirrors the api change in recoupable/api#366 (a28deb25). /api/research has been the discovery primitive for the research endpoints since that commit, but the spec still described it as "Search for artists by name" and didn't advertise the new passthrough params. Spec additions: - Description now frames /api/research as the discovery primitive for /track, /playlist, /albums (via type=tracks/playlists/artists). - Recommends beta=true for ambiguous queries, citing the upstream bug where default-engine returns 1 low-quality match for common terms like "Hotline Bling" or "Flowers". - New params: beta (enum "true"/"false"), platforms (comma-separated, beta-only), offset (non-negative integer for pagination). - ResearchSearchResult schema loosened to reflect reality: the default engine and beta engine return different shapes, and default-engine shape varies by type. Common fields enumerated; additionalProperties: true keeps engine-specific fields passing through without over-specifying. Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 75 +++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index 6859a61..affca6a 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -804,13 +804,13 @@ }, "/api/research": { "get": { - "description": "Search for artists by name. Returns matching results with profile summaries.", + "description": "Unified Chartmetric search. This is the discovery primitive for the detail-lookup endpoints — use `type=artists` to find an `id` for `/api/research/albums`, `type=tracks` for `/api/research/track`, `type=playlists` for `/api/research/playlist`, etc. Pick the right `id` from the returned results and pass it to the appropriate detail endpoint.\n\nThin proxy over Chartmetric's `/search`. Chartmetric's default search engine is narrow — for ambiguous queries like `Hotline Bling` or `Flowers` it often returns a single low-quality match. **Pass `beta=true` for higher relevance and accuracy**, which switches Chartmetric to its improved ranking engine. Beta results include a numeric `match_strength` score and have a slightly different shape than the default engine (see the response schema).", "parameters": [ { "name": "q", "in": "query", "required": true, - "description": "Artist name to search for.", + "description": "Search query. Can be a name (e.g. `Drake`, `Flowers`) or a streaming-platform URL (e.g. `https://open.spotify.com/artist/...`).", "schema": { "type": "string" } @@ -819,7 +819,7 @@ "name": "type", "in": "query", "required": false, - "description": "Entity type.", + "description": "Entity type to search.", "schema": { "type": "string", "enum": [ @@ -842,6 +842,39 @@ "type": "integer", "default": 10 } + }, + { + "name": "beta", + "in": "query", + "required": false, + "description": "When `true`, switches Chartmetric to its improved beta search engine — recommended for ambiguous queries. Results come back sorted by `match_strength` (higher is better) and include `target`/`platform` fields instead of the default-mode shape.", + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + } + }, + { + "name": "platforms", + "in": "query", + "required": false, + "description": "Comma-separated platforms to include in beta results (e.g. `cm,spotify`). Only valid with `beta=true`; ignored otherwise.", + "schema": { + "type": "string", + "example": "cm,spotify" + } + }, + { + "name": "offset", + "in": "query", + "required": false, + "description": "Pagination offset. Defaults to 0 when omitted.", + "schema": { + "type": "string", + "pattern": "^(0|[1-9][0-9]*)$" + } } ], "responses": { @@ -4670,17 +4703,49 @@ }, "ResearchSearchResult": { "type": "object", + "description": "Shape varies by `type` and search engine. Common fields are listed here; `additionalProperties: true` lets engine-specific fields pass through.\n\n**Default engine (`beta=false`):** entries include `name`, `id`, `image_url`, plus type-specific fields like `artist_names[]` (tracks), `isrc` (tracks), `sp_followers`/`sp_monthly_listeners`/`cm_artist_score` (artists), `owner_name` (playlists), etc.\n\n**Beta engine (`beta=true`):** entries include `name`, `id`, `imageUrl`, `target` (the entity type — e.g. `track`, `artist`, `playlist`), `platform` (e.g. `cm`, `spotify`), and `match_strength` (numeric relevance score, higher is better).", "properties": { "name": { "type": "string" }, "id": { - "type": "integer", - "description": "Internal ID for use with other research endpoints." + "description": "Chartmetric internal ID for use with the detail-lookup endpoints (`/api/research/track`, `/api/research/playlist`, `/api/research/albums`, etc.). Usually an integer; some playlist sources return a string.", + "oneOf": [ + { "type": "integer" }, + { "type": "string" } + ] + }, + "image_url": { + "type": "string", + "nullable": true, + "description": "Default-engine image URL. (Beta engine returns `imageUrl` instead.)" + }, + "imageUrl": { + "type": "string", + "nullable": true, + "description": "Beta-engine image URL. (Default engine returns `image_url` instead.)" + }, + "match_strength": { + "type": "number", + "description": "Beta-only relevance score — sort entries by this descending. Not present in default-engine results." + }, + "target": { + "type": "string", + "description": "Beta-only entity type (`track`, `artist`, `playlist`, etc.). Not present in default-engine results." + }, + "platform": { + "type": "string", + "description": "Beta-only source platform (e.g. `cm`, `spotify`). Not present in default-engine results." }, "spotify_id": { "type": "string", "nullable": true + }, + "artist_names": { + "type": "array", + "nullable": true, + "items": { "type": "string" }, + "description": "Default-engine tracks only." } }, "additionalProperties": true From 15bee59cc3e5906b0e6cb7cbc526f4a0fc35fa64 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 14:49:32 -0500 Subject: [PATCH 6/7] =?UTF-8?q?docs:=20link=20detail=20endpoints=20?= =?UTF-8?q?=E2=86=94=20/api/research=20search=20endpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The discovery-then-detail flow is core to the new "one call per endpoint" design, so the references between endpoints should be clickable — both for humans reading the docs and for LLMs using the .md sitemap. Per the existing convention (e.g. the chat endpoints already use [text](/api-reference/chat/update)), updated: - /research/playlist: link to /api-reference/research/search in both the endpoint description and the `id` param description - /research/track: same, in both places - /research/albums: same, in both places - /api/research (search): forward-links to the three detail endpoints (/albums, /track, /playlist) in the endpoint description Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index affca6a..4164e57 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -804,7 +804,7 @@ }, "/api/research": { "get": { - "description": "Unified Chartmetric search. This is the discovery primitive for the detail-lookup endpoints — use `type=artists` to find an `id` for `/api/research/albums`, `type=tracks` for `/api/research/track`, `type=playlists` for `/api/research/playlist`, etc. Pick the right `id` from the returned results and pass it to the appropriate detail endpoint.\n\nThin proxy over Chartmetric's `/search`. Chartmetric's default search engine is narrow — for ambiguous queries like `Hotline Bling` or `Flowers` it often returns a single low-quality match. **Pass `beta=true` for higher relevance and accuracy**, which switches Chartmetric to its improved ranking engine. Beta results include a numeric `match_strength` score and have a slightly different shape than the default engine (see the response schema).", + "description": "Unified Chartmetric search. This is the discovery primitive for the detail-lookup endpoints — use `type=artists` to find an `id` for [GET /api/research/albums](/api-reference/research/albums), `type=tracks` for [GET /api/research/track](/api-reference/research/track), `type=playlists` for [GET /api/research/playlist](/api-reference/research/playlist), etc. Pick the right `id` from the returned results and pass it to the appropriate detail endpoint.\n\nThin proxy over Chartmetric's `/search`. Chartmetric's default search engine is narrow — for ambiguous queries like `Hotline Bling` or `Flowers` it often returns a single low-quality match. **Pass `beta=true` for higher relevance and accuracy**, which switches Chartmetric to its improved ranking engine. Beta results include a numeric `match_strength` score and have a slightly different shape than the default engine (see the response schema).", "parameters": [ { "name": "q", @@ -913,13 +913,13 @@ }, "/api/research/albums": { "get": { - "description": "Get the album discography — albums, EPs, and singles with release dates — for a Chartmetric `artist_id`.\n\nThin proxy over Chartmetric's `/artist/:id/albums`. By default `is_primary=true`, so only albums where the artist is a main artist are returned — DJ compilations, soundtracks, and pure feature appearances are excluded. Pass `is_primary=false` to include them. Discovery by name is the caller's job via `GET /api/research?q=&type=artists&beta=true`.", + "description": "Get the album discography — albums, EPs, and singles with release dates — for a Chartmetric `artist_id`.\n\nThin proxy over Chartmetric's `/artist/:id/albums`. By default `is_primary=true`, so only albums where the artist is a main artist are returned — DJ compilations, soundtracks, and pure feature appearances are excluded. Pass `is_primary=false` to include them. Discover a Chartmetric `artist_id` via [GET /api/research](/api-reference/research/search) with `type=artists&beta=true`.", "parameters": [ { "name": "artist_id", "in": "query", "required": true, - "description": "Chartmetric artist ID (positive integer). Obtain via `GET /api/research?type=artists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", + "description": "Chartmetric artist ID (positive integer). Obtain via [GET /api/research](/api-reference/research/search) with `type=artists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", "schema": { "type": "string", "pattern": "^[1-9][0-9]*$", @@ -1949,7 +1949,7 @@ }, "/api/research/playlist": { "get": { - "description": "Get playlist metadata — name, description, follower count, track count, and curator info.\n\nThin proxy over Chartmetric's `/playlist/:platform/:id` detail lookup. **`id` is Chartmetric's own numeric playlist ID, not the streaming-platform's native ID.** Discovery is the caller's job via `GET /api/research?q=&type=playlists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", + "description": "Get playlist metadata — name, description, follower count, track count, and curator info.\n\nThin proxy over Chartmetric's `/playlist/:platform/:id` detail lookup. **`id` is Chartmetric's own numeric playlist ID, not the streaming-platform's native ID.** Discover the Chartmetric playlist ID via [GET /api/research](/api-reference/research/search) with `type=playlists&beta=true` — the `id` field in each result is the Chartmetric ID to pass here.", "parameters": [ { "name": "platform", @@ -1971,7 +1971,7 @@ "name": "id", "in": "query", "required": true, - "description": "Chartmetric playlist ID (positive integer). This is **not** the streaming platform's native ID — e.g. Spotify's base62 ID `37i9dQZF1DXcBWIGoYBM5M` for RapCaviar maps to Chartmetric ID `848051`. Obtain via `GET /api/research?type=playlists&beta=true`.", + "description": "Chartmetric playlist ID (positive integer). This is **not** the streaming platform's native ID — e.g. Spotify's base62 ID `37i9dQZF1DXcBWIGoYBM5M` for RapCaviar maps to Chartmetric ID `848051`. Obtain via [GET /api/research](/api-reference/research/search) with `type=playlists&beta=true`.", "schema": { "type": "string", "pattern": "^[1-9][0-9]*$", @@ -2419,13 +2419,13 @@ }, "/api/research/track": { "get": { - "description": "Get full Chartmetric track metadata by numeric track `id` — title, artists, albums, release date, genres, popularity, and platform IDs.\n\nThis endpoint is a thin proxy over Chartmetric's `/track/:id` detail lookup. Discovery by name is the caller's job: use `GET /api/research?q=&type=tracks&beta=true` to search, pick a result's `id`, then call this endpoint. Keeping the two concerns separate means predictable credit charging and no silent wrong-match behavior for ambiguous queries.", + "description": "Get full Chartmetric track metadata by numeric track `id` — title, artists, albums, release date, genres, popularity, and platform IDs.\n\nThis endpoint is a thin proxy over Chartmetric's `/track/:id` detail lookup. Discover a Chartmetric track ID via [GET /api/research](/api-reference/research/search) with `type=tracks&beta=true` — pick a result's `id`, then call this endpoint. Keeping the two concerns separate means predictable credit charging and no silent wrong-match behavior for ambiguous queries.", "parameters": [ { "name": "id", "in": "query", "required": true, - "description": "Chartmetric track ID (positive integer). Obtain via `GET /api/research?type=tracks&beta=true` — beta-ranked search results include the `id` field directly.", + "description": "Chartmetric track ID (positive integer). Obtain via [GET /api/research](/api-reference/research/search) with `type=tracks&beta=true` — beta-ranked search results include the `id` field directly.", "schema": { "type": "string", "pattern": "^[1-9][0-9]*$", From 9aa8f61a597944b6b71829b293c1a9b86e1f132c Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 16 Apr 2026 14:51:19 -0500 Subject: [PATCH 7/7] docs: /research/curator and /research/track/playlists link to search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit of Chartmetric-id params after 15bee59 found two more endpoints that require a numeric Chartmetric ID but didn't link to the discovery endpoint: - /research/curator (id): now links to GET /api/research?type=curators&beta=true. Kept the existing hint about finding curators via /research/playlists as a secondary path. - /research/track/playlists (id): now links to GET /api/research?type=tracks&beta=true. (Note: this endpoint still has a composite `q`/`artist` name-lookup fallback with the same wrong-match risk as the old /research/track behavior; KISS-ifying it is a separate follow-up.) All five endpoints that reference a Chartmetric id now point callers at the same discovery primitive: /research/albums (artist_id) ✓ /research/curator (id) ✓ /research/playlist (id) ✓ /research/track (id) ✓ /research/track/playlists (id) ✓ Co-Authored-By: Claude Opus 4.7 (1M context) --- api-reference/openapi/research.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api-reference/openapi/research.json b/api-reference/openapi/research.json index 4164e57..7b2b730 100644 --- a/api-reference/openapi/research.json +++ b/api-reference/openapi/research.json @@ -1253,7 +1253,7 @@ }, "/api/research/curator": { "get": { - "description": "Get curator profile — name, image, follower counts across platforms, tag-based genre info, and Chartmetric playlist reach statistics. Requires a numeric Chartmetric curator ID (e.g. `2` for Spotify's own account). Use `GET /api/research/playlists` to discover curators via their playlists.", + "description": "Get curator profile — name, image, follower counts across platforms, tag-based genre info, and Chartmetric playlist reach statistics. Requires a numeric Chartmetric curator ID (e.g. `2` for Spotify's own account). Discover a Chartmetric curator ID via [GET /api/research](/api-reference/research/search) with `type=curators&beta=true`. You can also find curators indirectly by looking up their playlists via [GET /api/research/playlists](/api-reference/research/playlists).", "parameters": [ { "name": "platform", @@ -1273,7 +1273,7 @@ "name": "id", "in": "query", "required": true, - "description": "Numeric Chartmetric curator ID (e.g. `2` for Spotify's own account). Non-numeric values will be rejected.", + "description": "Numeric Chartmetric curator ID (e.g. `2` for Spotify's own account). Non-numeric values will be rejected. Obtain via [GET /api/research](/api-reference/research/search) with `type=curators&beta=true`.", "schema": { "type": "string", "pattern": "^[0-9]+$", @@ -2670,12 +2670,12 @@ }, "/api/research/track/playlists": { "get": { - "description": "Returns playlists featuring a specific track. Accepts a Chartmetric track ID (`id`) or a track name + optional artist (`q`, `artist`) for a Spotify-powered lookup. When no filter flag is passed, defaults to editorial + indie + majorCurator + popularIndie = `true`. Costs 5 credits per request.", + "description": "Returns playlists featuring a specific track. Accepts a Chartmetric track ID (`id`) or a track name + optional artist (`q`, `artist`) for a Spotify-powered lookup. When no filter flag is passed, defaults to editorial + indie + majorCurator + popularIndie = `true`. Costs 5 credits per request.\n\nDiscover a Chartmetric track `id` via [GET /api/research](/api-reference/research/search) with `type=tracks&beta=true` — then pass the resulting `id` here for the most reliable match (avoids the ambiguity of name-based lookup).", "parameters": [ { "name": "id", "in": "query", - "description": "Chartmetric track ID. Required if `q` is not provided.", + "description": "Chartmetric track ID. Required if `q` is not provided. Obtain via [GET /api/research](/api-reference/research/search) with `type=tracks&beta=true`.", "schema": { "type": "string" }