checkleaked-spotify-api
Typed Python SDK for the Spotify Data API, covering the same 106 methods
and 23 namespaces as
@checkleaked/spotify-api.
It works with both the
RapidAPI spotify81 API
and the direct
CheckLeaked API.
This is a data API client. It does not require Spotify OAuth credentials.
Links: API reference · Status page · Changelog · Support: admin@checkleaked.cc
Install
pip install checkleaked-spotify-api
Quick start
from spotify_api_sdk import SpotifyApiClient
spotify = SpotifyApiClient(api_key="your-rapidapi-key")
# Play counts for up to 50 tracks per call
counts = spotify.tracks.counts(
["0VjIjW4GlUZAMYd2vXMi3b", "spotify:track:7ouMYWpwJ422jRcDASZB7P"]
)
results = spotify.search.search(
"daft punk",
type="artists",
limit=5,
)
# slim=True drops the heavy blocks; stats and top tracks are kept
artist = spotify.artists.overview(
"spotify:artist:4tZwfgrHOc3mvqYlEYSvVi",
slim=True,
)
lyrics = spotify.tracks.lyrics(
"https://open.spotify.com/track/0DiWol3AO6WpXZgp0goxAV",
format="lrc",
)
status = spotify.status() # per-endpoint-family service status
Methods return the API's payload. Endpoints that wrap it in
{success, data, metadata} are unwrapped to data; use
client.request_raw(...) when you need the complete envelope.
Play counts
| Need | Method |
|---|---|
| Many tracks (up to 50 per call) | tracks.counts(ids) |
| One track, by id or ISRC | partner.track_count(spotify_track_id=...) / (isrc=...) |
| Track + album + artists + play count | partner.track(id, slim=True) |
| Every track of an album | partner.album(id) or albums.tracks(id) |
| Every track of a playlist | partner.playlist(id) |
Spotify reports 0 for tracks with fewer than 1,000 plays. tracks.counts
needs an API release that serves /partner/tracks/count; an older deployment
answers 404, so fall back to partner.track_count() per id.
Providers
RapidAPI is the default and automatically adds
x-rapidapi-host: spotify81.p.rapidapi.com:
spotify = SpotifyApiClient(
api_key="your-rapidapi-key",
provider="rapidapi",
)
The direct API exposes the same methods and paths. Use a key issued by the direct portal:
spotify = SpotifyApiClient(
api_key="your-direct-api-key",
provider="proxy",
)
The API key may be omitted when SPOTIFY_API_KEY or RAPIDAPI_KEY is set.
Pythonic and npm-compatible names
Python methods use snake_case, while npm-style camelCase aliases are also
available:
spotify.artists.top_tracks(id, market="US")
spotify.artists.topTracks(id, market="US") # exact npm-style alias
Every method supports per-call request_timeout, request_retries,
request_headers, and an additional extra_query mapping. POST methods also
accept a free-form body mapping. The timeout argument of
search.search() is different: it is the API's own search budget in
milliseconds, and it can only shorten a search, which ends within about 20
seconds anyway.
Responses are cached for a while (play counts about an hour, catalog objects up
to a day). Pass extra_query={"cache": "false"} to skip the cached copy; a
given URL is refreshed at most once every 10 seconds.
IDs, URIs, and URLs
Spotify IDs may be supplied as bare IDs, Spotify URIs, or open.spotify.com URLs. Multi-ID methods accept comma-separated strings or Python sequences.
from spotify_api_sdk import normalize_id, normalize_ids
normalize_id("spotify:track:0DiWol3AO6WpXZgp0goxAV")
normalize_ids([
"spotify:artist:4tZwfgrHOc3mvqYlEYSvVi",
"https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
])
Spotify relinks some tracks to another id in a market: tracks.get then
returns an object whose id differs from the one you asked for, with
linked_from.id set to your id.
tracks.get, albums.get and artists.get leave out ids they have no object
for and list them in one of two arrays: missing means Spotify does not know
the id (asking again will not help); unavailable means it could not be
fetched this time, so ask for those ids again later. When none of the ids
could be fetched, the call raises a 503 UPSTREAM_UNAVAILABLE error instead
(retried automatically). tracks.get_by_id raises 404 for an id Spotify does
not know and 503 when it could not be fetched.
result = spotify.tracks.get(ids)
retry_later = result.get("unavailable", []) # ask again later
not_on_spotify = result.get("missing", []) # drop for good
Pagination
from spotify_api_sdk import collect
items = collect(
lambda **page: spotify.artists.albums(id=artist_id, **page),
get_items=lambda response: (
response.get("data", {})
.get("artist", {})
.get("discography", {})
.get("albums", {})
.get("items", [])
),
limit=50,
max_items=500,
)
Errors
Every failure raises a SpotifyApiError subclass. A 2xx body that reports a
failure (success: false, error: true, or an error code such as
LYRICS_NOT_AVAILABLE for a track without lyrics) raises too.
from spotify_api_sdk import (
AuthError,
HttpError,
RateLimitError,
SpotifyApiError,
TimeoutError,
)
try:
spotify.search.search("daft punk")
except RateLimitError as error:
print(error.code, error.retry_after_ms) # RATE_LIMITED / QUOTA_EXCEEDED
except AuthError:
print("Invalid or unsubscribed API key")
except SpotifyApiError as error:
print(error.status, error.code, error.request_id, error.param, error.retryable)
| HTTP | code |
Meaning |
|---|---|---|
| 400 | INVALID_PARAMETER, MISSING_PARAMETER |
Fix the request (error.param) |
| 401 | MISSING_API_KEY, INVALID_API_KEY, KEY_REVOKED, KEY_EXPIRED |
Key problem |
| 404 | NOT_FOUND, UNKNOWN_ENDPOINT |
Entity or route does not exist |
| 422 | VIDEO_UNAVAILABLE, AGE_RESTRICTED, PREMIUM_ONLY |
Downloads only |
| 429 | RATE_LIMITED, QUOTA_EXCEEDED |
Your rate limit or quota |
| 503 | UPSTREAM_UNAVAILABLE, UPSTREAM_THROTTLED, UPSTREAM_TIMEOUT, LOAD_SHED |
Temporary, retried automatically |
| 503 | OUTCOME_UNKNOWN |
A request that changes something may or may not have run: never retried automatically, check its effect first |
Spotify-side problems arrive as 503 with Retry-After, never as 401/429.
The API never answers 502 or 504: a request that runs out of time is a 503
UPSTREAM_TIMEOUT (it was a 504 before 2026-10). A plain-text 502, 504 or
524 comes from the network edge: a 504 or 524 (the edge stopped waiting, after
about 100 s) counts as a timeout, a 502 is retried like any other 5xx.
429 and 5xx responses are retried with backoff, honoring Retry-After (or the
body's retry_after_s); errors that waiting cannot fix (QUOTA_EXCEEDED, a
bad or revoked key, retryable: false) are raised immediately. No single wait
is longer than max_retry_delay (default 10 seconds), even when Retry-After
asks for more (error.retry_after_ms still reports what the API asked for).
A timeout (a 503 whose code is UPSTREAM_TIMEOUT, or a 504 or 524 from the
edge) means the API already spent its whole time budget on the request, so it
is retried at most gateway_timeout_retries times (default once); every
other 5xx can use all retries.
Quote error.request_id when you contact support.
Tracking and webhooks
spotify.tracking.track("artist", "06HL4z0CvFAxyc27GXpf02", label="Taylor")
changes = spotify.tracking.logs(
spotify_type="artist",
change_type="monthly_listeners_change",
)
spotify.webhooks.register(
"37i9dQZF1DXcBWIGoYBM5M",
"https://example.com/spotify-hook",
events=["playlist.tracks.added", "playlist.tracks.removed"],
)
Tracked items and webhooks belong to the calling account; RapidAPI identifies you automatically. Tracking also works with a direct API key; webhooks are not available with direct API keys yet.
Configuration
spotify = SpotifyApiClient(
api_key="...",
provider="rapidapi", # rapidapi (default) | proxy
timeout=30,
retries=2,
retry_delay=0.5,
max_retry_delay=10, # longest wait before a retry, in seconds
gateway_timeout_retries=1, # retries a timeout may use (0 = never)
headers={"x-my-header": "value"},
debug=True,
on_request=lambda info: print("request", info["url"]),
on_response=lambda info: print("response", info["status"]),
on_retry=lambda info: print("retry", info["attempt"]),
)
The client is also a context manager:
with SpotifyApiClient(api_key="...") as spotify:
markets = spotify.markets.get()
See API_REFERENCE.md for every namespace and method.
Metadata
Release files for checkleaked-spotify-api 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| checkleaked_spotify_api-2.0.1.tar.gz | 40.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| checkleaked_spotify_api-2.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.6 kB
Release files / checkleaked_spotify_api-2.0.1.tar.gz
| Download URL | checkleaked_spotify_api-2.0.1.tar.gz |
|---|---|
| Size | 40.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e86990c7cfcf0833657e2bc01f37e9380b8260d81bac8d9cc5786d5667912bb2
|
|
BLAKE2b-256 checksum How to use checksums |
f6f1d850d52662addcdd5dc83f84e04dd61aaa913f4a3b94e44783c843442bcb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.6
|
Release files / checkleaked_spotify_api-2.0.1-py3-none-any.whl
| Download URL | checkleaked_spotify_api-2.0.1-py3-none-any.whl |
|---|---|
| Size | 27.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a11ac8992337768bb9d8ca4a9a4321644a821552f39868d89a098282f7409283
|
|
BLAKE2b-256 checksum How to use checksums |
39468108d4add46620c67ec9eb7ac8665021abef9d8cff9a8d24b9374fd74a42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.6
|