Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 240 additions & 0 deletions api-reference/openapi/research.json
Original file line number Diff line number Diff line change
Expand Up @@ -2500,6 +2500,174 @@
}
}
}
},
"/api/research/track/stats": {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this endpoint structure follow REST best practices?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — it follows the established convention: /api/research/track/playlists ("Track Playlists") is the direct precedent for a track/<sub-resource> endpoint, and like the rest of the research family it takes the identifier as a query param (?isrc=) rather than a path param. So /api/research/track/stats mirrors /api/research/track/playlists exactly — no change.

"get": {
"description": "Get per-track, per-source current stats by ISRC or track id — absolute `streams_total`, playlist reach, and chart counts.",
"parameters": [
{
"name": "isrc",
"in": "query",
"required": false,
"description": "Track ISRC. Provide exactly one track identifier.",
"schema": {
"type": "string",
"example": "USQY51771120"
}
},
{
"name": "songstats_track_id",
"in": "query",
"required": false,
"description": "Songstats track id (from `GET /api/research/tracks`).",
"schema": {
"type": "string"
}
},
{
"name": "spotify_track_id",
"in": "query",
"required": false,
"description": "Spotify track id.",
"schema": {
"type": "string"
}
},
{
"name": "apple_music_track_id",
"in": "query",
"required": false,
"description": "Apple Music track id.",
"schema": {
"type": "string"
}
},
{
"name": "source",
"in": "query",
"required": true,
"description": "Comma-separated list of sources, or `all`. e.g. `spotify`, `apple_music`, `deezer`, `youtube`.",
"schema": {
"type": "string",
"example": "spotify"
}
},
{
"name": "with_playlists",
"in": "query",
"required": false,
"description": "Include the per-source `playlists[]` array in `data`.",
"schema": {
"type": "boolean"
}
},
{
"name": "with_charts",
"in": "query",
"required": false,
"description": "Include the per-source `charts[]` array in `data`.",
"schema": {
"type": "boolean"
}
},
{
"name": "with_stations",
"in": "query",
"required": false,
"description": "Include radio `stations[]` data where available.",
"schema": {
"type": "boolean"
}
},
{
"name": "with_videos",
"in": "query",
"required": false,
"description": "Include video data where available.",
"schema": {
"type": "boolean"
}
},
{
"name": "with_links",
"in": "query",
"required": false,
"description": "Include external links where available.",
"schema": {
"type": "boolean"
}
},
{
"name": "only_current",
"in": "query",
"required": false,
"description": "Return only current counters, omitting historical/total breakdowns where applicable.",
"schema": {
"type": "boolean"
}
},
{
"name": "limit",
"in": "query",
"required": false,
"description": "Max items in toggled arrays (e.g. `playlists[]`).",
"schema": {
"type": "integer"
}
},
{
"name": "offset",
"in": "query",
"required": false,
"description": "Pagination offset for toggled arrays.",
"schema": {
"type": "integer"
}
}
],
"responses": {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Missing 501 ResearchDataSourceUnsupported response — all other research endpoints include it, and this endpoint is subject to the same data-source configuration constraints.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/openapi/research.json, line 2628:

<comment>Missing `501` `ResearchDataSourceUnsupported` response — all other research endpoints include it, and this endpoint is subject to the same data-source configuration constraints.</comment>

<file context>
@@ -2500,6 +2500,174 @@
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Per-track current stats, one entry per requested source.",
</file context>

"200": {
"description": "Per-track current stats, one entry per requested source.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResearchTrackStatsResponse"
}
}
}
},
"400": {
"description": "Validation error — missing identifier or `source`.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResearchErrorResponse"
}
}
}
},
"401": {
"description": "Authentication failed — invalid or missing API key.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResearchErrorResponse"
}
}
}
},
"404": {
"description": "No track matched the supplied identifier.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResearchErrorResponse"
}
}
}
}
}
Comment on lines +2628 to +2669

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the standard 501 unsupported-data-source response for this research endpoint.

GET /api/research/track/stats is missing the 501 response used by sibling research endpoints in this spec, which leaves generated docs/SDKs with an incomplete error contract.

Proposed fix
         "responses": {
           "200": {
             "description": "Per-track current stats, one entry per requested source.",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "`#/components/schemas/ResearchTrackStatsResponse`"
                 }
               }
             }
           },
           "400": {
             "description": "Validation error — missing identifier or `source`.",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "`#/components/schemas/ResearchErrorResponse`"
                 }
               }
             }
           },
           "401": {
             "description": "Authentication failed — invalid or missing API key.",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "`#/components/schemas/ResearchErrorResponse`"
                 }
               }
             }
           },
           "404": {
             "description": "No track matched the supplied identifier.",
             "content": {
               "application/json": {
                 "schema": {
                   "$ref": "`#/components/schemas/ResearchErrorResponse`"
                 }
               }
             }
+          },
+          "501": {
+            "$ref": "`#/components/responses/ResearchDataSourceUnsupported`"
           }
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-reference/openapi/research.json` around lines 2628 - 2669, Add the
standard 501 response to the GET /api/research/track/stats endpoint responses:
include a "501" entry with a brief description (e.g., "Unsupported data source")
and the same application/json content/schema as the other error responses by
referencing the existing ResearchErrorResponse schema; update the responses
object for this endpoint so it matches sibling research endpoints that return
501 for unsupported data sources.

}
}
},
"components": {
Expand Down Expand Up @@ -4411,6 +4579,10 @@
"type": "object",
"description": "Full track record.",
"properties": {
"songstats_track_id": {
"type": "string",
"description": "Songstats track id — pass to `GET /api/research/track/stats` or `GET /api/research/track`."
},
"title": {
"type": "string"
},
Expand Down Expand Up @@ -4472,6 +4644,74 @@
}
},
"additionalProperties": true
},
"ResearchTrackStatsResponse": {
"type": "object",
"description": "Per-track current statistics for the requested `source`(s). Mirrors `ResearchMetricsResponse`, scoped to a single recording.",
"properties": {
"status": {
"type": "string",
"example": "success"
},
"result": {
"type": "string",
"example": "success"
},
"message": {
"type": "string",
"example": "Data Retrieved."
},
"stats": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ResearchTrackStat"
}
},
"track_info": {
"$ref": "#/components/schemas/ResearchTrackInfo"
},
"source_ids": {
"type": "array",
"description": "All source identifiers Songstats tracks for this recording — a superset of the sources returned in `stats`.",
"items": {
"type": "string"
}
}
}
},
"ResearchTrackStat": {
"type": "object",
"description": "Per-source current statistics for a single track.",
"properties": {
"source": {
"type": "string",
"description": "Platform the stats belong to, e.g. `spotify`, `apple_music`, `deezer`, `youtube`."
},
"data": {
"type": "object",
"description": "Per-source counters for this track. `streams_total` is the absolute play count. Keys vary by `source`; optional `playlists[]` / `charts[]` / `reposters[]` arrays appear when the matching `with_*` toggle is set.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The data field description references reposters[] but there is no with_reposters query parameter. The actual toggles are with_playlists, with_charts, with_stations, with_videos, and with_links — the description should list stations[] / videos[] / links[] instead of reposters[].

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/openapi/research.json, line 4681:

<comment>The `data` field description references `reposters[]` but there is no `with_reposters` query parameter. The actual toggles are `with_playlists`, `with_charts`, `with_stations`, `with_videos`, and `with_links` — the description should list `stations[]` / `videos[]` / `links[]` instead of `reposters[]`.</comment>

<file context>
@@ -4472,6 +4640,65 @@
+          },
+          "data": {
+            "type": "object",
+            "description": "Per-source counters for this track. `streams_total` is the absolute play count. Keys vary by `source`; optional `playlists[]` / `charts[]` / `reposters[]` arrays appear when the matching `with_*` toggle is set.",
+            "additionalProperties": true,
+            "example": {
</file context>
Suggested change
"description": "Per-source counters for this track. `streams_total` is the absolute play count. Keys vary by `source`; optional `playlists[]` / `charts[]` / `reposters[]` arrays appear when the matching `with_*` toggle is set.",
"description": "Per-source counters for this track. `streams_total` is the absolute play count. Keys vary by `source`; optional `playlists[]` / `charts[]` / `stations[]` / `videos[]` / `links[]` fields can appear based on the corresponding `with_*` toggles.",

"additionalProperties": true,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"example": {
"streams_total": 84213771,
"popularity_current": 64,
"playlists_current": 1200,
"playlists_total": 4830,
"playlist_reach_current": 18450201,
"playlist_reach_total": 51200988,
"charts_current": 3,
"charts_total": 41,
"shazams_total": 220145,
"charted_cities_total": 87,
"charted_countries_total": 23,
"favorites_total": 0,
"reposts_total": 0,
"engagement_rate_total": 0,
"playlists_editorial_current": 12,
"playlists_editorial_total": 58
}
}
},
"additionalProperties": true
}
},
"responses": {
Expand Down
4 changes: 4 additions & 0 deletions api-reference/research/track-stats.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: 'Track Stats'
openapi: "/api-reference/openapi/research.json GET /api/research/track/stats"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the required API-reference openapi frontmatter format.

Line 3 uses a non-standard openapi value format for this repo’s API-reference pages.

Proposed fix
-openapi: "/api-reference/openapi/research.json GET /api/research/track/stats"
+openapi: 'GET /api/research/track/stats'

As per coding guidelines, API reference MDX pages must be frontmatter-only and use openapi: 'METHOD /path'.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
openapi: "/api-reference/openapi/research.json GET /api/research/track/stats"
openapi: 'GET /api/research/track/stats'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-reference/research/track-stats.mdx` at line 3, Replace the non-standard
frontmatter value with the required API-reference frontmatter format: change the
openapi entry from openapi: "/api-reference/openapi/research.json GET
/api/research/track/stats" to openapi: 'GET /api/research/track/stats' and
ensure the MDX file is frontmatter-only (no other content outside the YAML
frontmatter block).

Source: Coding guidelines

---
3 changes: 2 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@
"pages": [
"api-reference/research/albums",
"api-reference/research/tracks",
"api-reference/research/track"
"api-reference/research/track",
"api-reference/research/track-stats"
]
},
{
Expand Down