Spotify API
The TrueScrape Spotify API exposes 7 public endpoints covering Album details, Artist details, Playlist contents, Podcast details, Podcast episodes and Search. Every call is a GET against public, logged-out pages and returns the same unified schema as every other platform here. Calls cost 1 credit each. A cache hit is free, and a failed or empty response is never charged.
Endpoints
| Endpoint | Returns | Credits | Cacheable | Batchable |
|---|---|---|---|---|
| /v1/spotify/album | Album details | 1 | yes | yes |
| /v1/spotify/artist | Artist details | 1 | yes | yes |
| /v1/spotify/playlist | Playlist contents | 1 | yes | yes |
| /v1/spotify/podcast | Podcast details | 1 | yes | yes |
| /v1/spotify/podcast/episodes | Podcast episodes | 1 | yes | yes |
| /v1/spotify/search | Search | 1 | yes | yes |
| /v1/spotify/track | Track details | 1 | yes | yes |
Reference
/v1/spotify/album1 creditcacheablebatchableAlbum details
Public Spotify album: title, artist, release date, artwork and total runtime. The track listing, release type (album or single) and track count are in raw. Add include_raw=true.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | Spotify album id, spotify:album: URI, or open.spotify.com album URL |
| url | string | no | Spotify album id, spotify:album: URI, or open.spotify.com album URL |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns one Post.
Fields
| Field | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | |
| type | video | short | image | carousel | text | live | story | reel | audio | album | episode | unknown | always | What kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else. |
| url | string | null | always | |
| title | string | null | always | |
| text | string | null | always | The post's text: a caption, a description or the message body. |
| authorId | string | null | always | |
| authorHandle | string | null | always | |
| authorName | string | null | always | |
| thumbnailUrl | string | null | always | |
| mediaUrls | string[] | always | |
| durationSeconds | number | null | always | |
| viewCount | number | null | always | Views. Null means the platform did not expose a count, which is not the same as zero. |
| likeCount | number | null | always | Likes, or the platform's nearest equivalent. Null means not exposed, not zero. |
| commentCount | number | null | always | Comments. Null means not exposed, not zero. |
| shareCount | number | null | always | Shares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero. |
| hashtags | string[] | always | Hashtags or the platform's own topic tags, without the leading #. |
| mentions | string[] | always | Handles mentioned in the post text, without the leading @. |
| taggedUsers | string[] | may be absent | Usernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none. |
| isSponsored | boolean | null | always | Whether the platform labels the post as an ad, promoted content or a paid partnership. |
| publishedAt | string | null | always | When the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago". |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/album?id=%3Cid%3E&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
id: '<id>',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/album?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/album",
params={
"id": "<id>",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/artist1 creditcacheablebatchableArtist details
Public Spotify artist: name, exact follower count, biography, artwork and external links. Monthly listeners and current top tracks with play counts are in raw.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | Spotify artist id, spotify:artist: URI, or open.spotify.com artist URL |
| url | string | no | Spotify artist id, spotify:artist: URI, or open.spotify.com artist URL |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns one Creator.
Fields
| Field | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | The platform's own id for the account, such as a channel id or a numeric user id, always as a string. |
| handle | string | null | always | The account handle without the leading @. Null when the platform has no handles. |
| displayName | string | null | always | |
| bio | string | null | always | |
| avatarUrl | string | null | always | |
| bannerUrl | string | null | always | |
| url | string | null | always | |
| verified | boolean | null | always | Whether the platform shows a verification badge on the account. Null where the platform has no public badge or does not expose it. |
| followerCount | number | null | always | Followers, subscribers, or the platform's nearest equivalent. Null when the account hides the count or the platform does not expose it. |
| followingCount | number | null | always | |
| postCount | number | null | always | Posts, videos, tracks, repositories, or the platform's nearest equivalent that the account has published. |
| viewCount | number | null | always | Lifetime views across the account, where the platform exposes a total. |
| likeCount | number | null | may be absent | Total likes received across all of the creator's posts. Distinct from `viewCount`. Absent when the platform does not expose it. |
| isPrivate | boolean | null | always | |
| isBusiness | boolean | null | always | Whether the platform classifies the account as a business or organisation rather than a person or creator. Null where the platform draws no such line or does not expose it. On Facebook every Page counts, including Pages for public figures. |
| category | string | null | always | A label the platform attaches to the account, such as a business category, a genre or an account type. What it holds varies by platform. |
| location | string | null | always | Location as the platform shows it: a city, a country, a region code or an address, depending on the platform. |
| externalLinks | string[] | always | Links the account lists on its profile, such as a website or other social accounts. |
| createdAt | string | null | always | When the account was created. Usually an ISO 8601 timestamp; some platforms expose only the date as shown on the profile. |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/artist?id=%3Cid%3E&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
id: '<id>',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/artist?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/artist",
params={
"id": "<id>",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/playlist1 creditcacheablebatchablePlaylist contents
Public Spotify playlist: name, owner, description, cover art, total track count and its tracks, 50 per cursor page, up to the first 100. On a longer playlist the last page reports hasMore true with a null cursor: the remaining tracks exist but are not served. **Required:** Pass exactly one of id or url.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | no | Spotify playlist id, spotify:playlist: URI, or open.spotify.com playlist URL |
| url | string | no | open.spotify.com playlist URL |
| cursor | string | no | Offset into the track list. Pass back pagination.cursor |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns an object with platform, id, name, url, ownerName, description, coverImageUrl, trackCount, items.
Fields
| Field | Type | Present |
|---|---|---|
| platform | "spotify" | always |
| id | string | always |
| name | string | null | always |
| url | string | always |
| ownerName | string | null | always |
| description | string | null | always |
| coverImageUrl | string | null | always |
| trackCount | number | null | always |
| items | Post[] | always |
curl "$API/v1/spotify/playlist?cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/playlist?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/playlist",
params={
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/podcast1 creditcacheablebatchablePodcast details
A Spotify podcast: title, publisher, description, artwork and episode count, with its rating and topics in raw. Two fields carry something different here than they do elsewhere: category holds the show's publisher, and postCount is its episode count. The unified schema has no publisher field, and naming it here is better than leaving you to infer it.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | Spotify show id, spotify:show: URI, or open.spotify.com show URL |
| market | string | no | ISO 3166-1 alpha-2 market codedefaults to US |
| url | string | no | Spotify show id, spotify:show: URI, or open.spotify.com show URL |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns one Creator.
Fields
| Field | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | The platform's own id for the account, such as a channel id or a numeric user id, always as a string. |
| handle | string | null | always | The account handle without the leading @. Null when the platform has no handles. |
| displayName | string | null | always | |
| bio | string | null | always | |
| avatarUrl | string | null | always | |
| bannerUrl | string | null | always | |
| url | string | null | always | |
| verified | boolean | null | always | Whether the platform shows a verification badge on the account. Null where the platform has no public badge or does not expose it. |
| followerCount | number | null | always | Followers, subscribers, or the platform's nearest equivalent. Null when the account hides the count or the platform does not expose it. |
| followingCount | number | null | always | |
| postCount | number | null | always | Posts, videos, tracks, repositories, or the platform's nearest equivalent that the account has published. |
| viewCount | number | null | always | Lifetime views across the account, where the platform exposes a total. |
| likeCount | number | null | may be absent | Total likes received across all of the creator's posts. Distinct from `viewCount`. Absent when the platform does not expose it. |
| isPrivate | boolean | null | always | |
| isBusiness | boolean | null | always | Whether the platform classifies the account as a business or organisation rather than a person or creator. Null where the platform draws no such line or does not expose it. On Facebook every Page counts, including Pages for public figures. |
| category | string | null | always | A label the platform attaches to the account, such as a business category, a genre or an account type. What it holds varies by platform. |
| location | string | null | always | Location as the platform shows it: a city, a country, a region code or an address, depending on the platform. |
| externalLinks | string[] | always | Links the account lists on its profile, such as a website or other social accounts. |
| createdAt | string | null | always | When the account was created. Usually an ISO 8601 timestamp; some platforms expose only the date as shown on the profile. |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/podcast?id=%3Cid%3E&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
id: '<id>',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/podcast?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/podcast",
params={
"id": "<id>",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/podcast/episodes1 creditcacheablebatchablePodcast episodes
Episodes for a Spotify podcast, newest first. Pass the cursor from the previous response to page. hasMore true with a null cursor means the show has more episodes than this response can page to.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | Spotify show id, spotify:show: URI, or open.spotify.com show URL |
| limit | number | no | defaults to 50 |
| cursor | string | no | pagination.cursor from the previous response |
| market | string | no | ISO 3166-1 alpha-2 market codedefaults to US |
| url | string | no | Spotify show id, spotify:show: URI, or open.spotify.com show URL |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns a list of Post in data.items.
Fields
| Field | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | |
| type | video | short | image | carousel | text | live | story | reel | audio | album | episode | unknown | always | What kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else. |
| url | string | null | always | |
| title | string | null | always | |
| text | string | null | always | The post's text: a caption, a description or the message body. |
| authorId | string | null | always | |
| authorHandle | string | null | always | |
| authorName | string | null | always | |
| thumbnailUrl | string | null | always | |
| mediaUrls | string[] | always | |
| durationSeconds | number | null | always | |
| viewCount | number | null | always | Views. Null means the platform did not expose a count, which is not the same as zero. |
| likeCount | number | null | always | Likes, or the platform's nearest equivalent. Null means not exposed, not zero. |
| commentCount | number | null | always | Comments. Null means not exposed, not zero. |
| shareCount | number | null | always | Shares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero. |
| hashtags | string[] | always | Hashtags or the platform's own topic tags, without the leading #. |
| mentions | string[] | always | Handles mentioned in the post text, without the leading @. |
| taggedUsers | string[] | may be absent | Usernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none. |
| isSponsored | boolean | null | always | Whether the platform labels the post as an ad, promoted content or a paid partnership. |
| publishedAt | string | null | always | When the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago". |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/podcast/episodes?id=%3Cid%3E&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
id: '<id>',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/podcast/episodes?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/podcast/episodes",
params={
"id": "<id>",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/search1 creditcacheablebatchableSearch
Search Spotify's catalogue for tracks, albums, artists, podcasts or episodes. Uses Spotify's official Web API, so this endpoint needs app credentials; everything else on this platform is keyless.
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | yes | Search terms |
| type | track | album | artist | show | episode | no | defaults to track |
| limit | number | no | defaults to 20 |
| market | string | no | ISO 3166-1 alpha-2 market codedefaults to US |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns a list of Post | Creator in data.items.
Fields
| Post | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | |
| type | video | short | image | carousel | text | live | story | reel | audio | album | episode | unknown | always | What kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else. |
| url | string | null | always | |
| title | string | null | always | |
| text | string | null | always | The post's text: a caption, a description or the message body. |
| authorId | string | null | always | |
| authorHandle | string | null | always | |
| authorName | string | null | always | |
| thumbnailUrl | string | null | always | |
| mediaUrls | string[] | always | |
| durationSeconds | number | null | always | |
| viewCount | number | null | always | Views. Null means the platform did not expose a count, which is not the same as zero. |
| likeCount | number | null | always | Likes, or the platform's nearest equivalent. Null means not exposed, not zero. |
| commentCount | number | null | always | Comments. Null means not exposed, not zero. |
| shareCount | number | null | always | Shares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero. |
| hashtags | string[] | always | Hashtags or the platform's own topic tags, without the leading #. |
| mentions | string[] | always | Handles mentioned in the post text, without the leading @. |
| taggedUsers | string[] | may be absent | Usernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none. |
| isSponsored | boolean | null | always | Whether the platform labels the post as an ad, promoted content or a paid partnership. |
| publishedAt | string | null | always | When the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago". |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
| Creator | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | The platform's own id for the account, such as a channel id or a numeric user id, always as a string. |
| handle | string | null | always | The account handle without the leading @. Null when the platform has no handles. |
| displayName | string | null | always | |
| bio | string | null | always | |
| avatarUrl | string | null | always | |
| bannerUrl | string | null | always | |
| url | string | null | always | |
| verified | boolean | null | always | Whether the platform shows a verification badge on the account. Null where the platform has no public badge or does not expose it. |
| followerCount | number | null | always | Followers, subscribers, or the platform's nearest equivalent. Null when the account hides the count or the platform does not expose it. |
| followingCount | number | null | always | |
| postCount | number | null | always | Posts, videos, tracks, repositories, or the platform's nearest equivalent that the account has published. |
| viewCount | number | null | always | Lifetime views across the account, where the platform exposes a total. |
| likeCount | number | null | may be absent | Total likes received across all of the creator's posts. Distinct from `viewCount`. Absent when the platform does not expose it. |
| isPrivate | boolean | null | always | |
| isBusiness | boolean | null | always | Whether the platform classifies the account as a business or organisation rather than a person or creator. Null where the platform draws no such line or does not expose it. On Facebook every Page counts, including Pages for public figures. |
| category | string | null | always | A label the platform attaches to the account, such as a business category, a genre or an account type. What it holds varies by platform. |
| location | string | null | always | Location as the platform shows it: a city, a country, a region code or an address, depending on the platform. |
| externalLinks | string[] | always | Links the account lists on its profile, such as a website or other social accounts. |
| createdAt | string | null | always | When the account was created. Usually an ISO 8601 timestamp; some platforms expose only the date as shown on the profile. |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/search?query=ai%20agents&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
query: 'ai agents',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/search?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/search",
params={
"query": "ai agents",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
/v1/spotify/track1 creditcacheablebatchableTrack details
Public Spotify track: title, artists, artwork, duration, release date and the preview clip URL. viewCount is the play count when the track is among its artist's top tracks, and null otherwise. The explicit-content label is in raw.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | yes | Spotify track id, spotify:track: URI, or open.spotify.com track URL |
| url | string | no | Spotify track id, spotify:track: URI, or open.spotify.com track URL |
Also accepts cache_max_age (a hit costs 0 credits) and include_raw (returns the untouched upstream payload under raw).
Returns one Post.
Fields
| Field | Type | Present | Description |
|---|---|---|---|
| platform | one of 32 strings | always | |
| id | string | always | |
| type | video | short | image | carousel | text | live | story | reel | audio | album | episode | unknown | always | What kind of post this is. `short` and `reel` are short-form video formats, `live` is a live stream or a recording of one, `carousel` holds several images or videos, `audio` is a music track, `album` is an album, `episode` is a podcast episode, and `unknown` covers anything else. |
| url | string | null | always | |
| title | string | null | always | |
| text | string | null | always | The post's text: a caption, a description or the message body. |
| authorId | string | null | always | |
| authorHandle | string | null | always | |
| authorName | string | null | always | |
| thumbnailUrl | string | null | always | |
| mediaUrls | string[] | always | |
| durationSeconds | number | null | always | |
| viewCount | number | null | always | Views. Null means the platform did not expose a count, which is not the same as zero. |
| likeCount | number | null | always | Likes, or the platform's nearest equivalent. Null means not exposed, not zero. |
| commentCount | number | null | always | Comments. Null means not exposed, not zero. |
| shareCount | number | null | always | Shares, reposts, or the platform's nearest equivalent. Null means not exposed, not zero. |
| hashtags | string[] | always | Hashtags or the platform's own topic tags, without the leading #. |
| mentions | string[] | always | Handles mentioned in the post text, without the leading @. |
| taggedUsers | string[] | may be absent | Usernames tagged in the media itself, as distinct from `mentions`, which come from the caption text. Absent when the platform does not report tags; an empty array means it reports none. |
| isSponsored | boolean | null | always | Whether the platform labels the post as an ad, promoted content or a paid partnership. |
| publishedAt | string | null | always | When the post was published. Usually an ISO 8601 timestamp; some platforms expose only a date or relative text such as "3 days ago". |
| fetchedAt | string | always | When this record was fetched from the platform, as an ISO 8601 timestamp. A cached response keeps the time of the original fetch. |
curl "$API/v1/spotify/track?id=%3Cid%3E&cache_max_age=7d" \
-H "x-api-key: $KEY"const query = new URLSearchParams({
id: '<id>',
cache_max_age: '7d',
});
const response = await fetch(`${API}/v1/spotify/track?${query}`, {
headers: { 'x-api-key': KEY },
});
const body = await response.json();
if (!body.success) throw new Error(body.error.code);
// 1 credit, 0 on a cache hit
console.log(body.data, body.meta.creditsCharged);Python
import os, httpx
r = httpx.get(
f"{os.environ['API']}/v1/spotify/track",
params={
"id": "<id>",
"cache_max_age": "7d",
},
headers={"x-api-key": os.environ["KEY"]},
timeout=30,
)
body = r.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
print(body["data"], body["meta"]["creditsCharged"])Response codes
| 200 | Success |
| 400 | invalid_request. Not charged |
| 401 | missing_api_key / invalid_api_key / revoked_api_key. Never a billing error |
| 402 | insufficient_credits. The key is valid, the balance is not |
| 429 | daily_cap_exceeded or upstream_rate_limited. Not charged |
| 501 | not_configured. This deployment is not set up to serve this endpoint. Not charged. |
| 502 | upstream_blocked / upstream_schema_drift. Not charged |
| 504 | upstream_timeout. Not charged |
Questions
- How much does the Spotify API cost?
- Calls cost 1 credit each. Every endpoint is cacheable, and a cache hit costs nothing. A failed request and an empty result are both free, on every endpoint.
- Does the Spotify API need a login or cookies?
- No. Every endpoint reads public, logged-out pages only — no account, no cookies, no session. An API key identifies your own TrueScrape account and nothing else.
- Can I fetch many Spotify targets in one request?
- Yes. 7 of 7 are batchable: one POST to /v1/jobs/batch takes many targets and returns a job id to poll.
- Can I watch Spotify endpoints for changes?
- Yes, 6 of 7. A subscription polls on your schedule and fires your webhook only when the content changed; the rest carry x-subscribable: false in the spec.