deezify
A complete, typed Python SDK for the Deezer API — every documented object, connection, search mode, write action, and the OAuth 2.0 login flows. Sync and async clients included.
- Base URL
https://api.deezer.com, quota50 requests / 5 seconds - No API key or login needed for public catalogue endpoints (track/album/artist/…)
access_token(OAuth) only for user-private actions (favorites, playlists, history…)- Paginated collections with
index/limit,next/prevwalking, anditer_all_items() - Built-in rate limiting (50 requests / 5 s sliding window) with automatic
retry on quota/busy responses — disable with
DeezerClient(rate_limit=False) - Typed responses:
Track,Album,Artist,Playlist,User,Chart, … withPaginatedList[Track]collections and IDE autocompletion - Typed dicts for every object, structured
DeezerAPIErrorwith documented codes
Install
pip install deezify
Requires Python ≥ 3.9 and httpx.
Quick start (no auth)
from deezify import DeezerClient
client = DeezerClient()
track = client.track.get(3135556) # "Harder, Better, Faster, Stronger"
print(track["title"], track["artist"]["name"])
results = client.search.all("Daft Punk", limit=5)
for t in results:
print(t["title"], "-", t["artist"]["name"])
top = client.artist.top(27) # top tracks of an artist
albums = client.chart.albums(limit=10) # global chart albums
print(client.infos.get()["country"]) # country info
Async works the same way:
import asyncio
from deezify import AsyncDeezerClient
async def main():
async with AsyncDeezerClient() as client:
track = await client.track.get(3135556)
print(track["title"])
asyncio.run(main())
Authenticated usage (OAuth)
from deezify import DeezerClient, authorization_url
# 1. Send the user to this URL (server-side flow)
url = authorization_url(
app_id="YOUR_APP_ID",
redirect_uri="https://your-app.example/callback",
perms="basic_access,email,offline_access",
state="random-csrf-token",
)
# 2. Deezer redirects back with ?code=... — exchange it:
client = DeezerClient()
token = client.exchange_code_for_token("YOUR_APP_ID", "YOUR_APP_SECRET", code)
client.set_access_token(token["access_token"])
me = client.user.me()
print(me["name"])
client.playlist.add_tracks(playlist_id=123, track_ids=[3135556])
For browser/mobile apps without a server secret, use the implicit flow:
from deezify import implicit_authorization_url, parse_implicit_callback_fragment
url = implicit_authorization_url("YOUR_APP_ID", "https://your-app.example/cb")
# ...after redirect, fragment looks like "access_token=...&expires=...":
token = parse_implicit_callback_fragment(fragment)
Needed permissions per action are documented on each method; the permission
names are basic_access, email, offline_access, manage_library, manage_community, delete_library, listening_history.
Coverage
| Area | Methods |
|---|---|
| Track | get, update_personal, delete_personal, favorites add/remove |
| Album | get, fans, tracks, library add/remove |
| Artist | get, top, albums, fans, related, radio, playlists, favorites add/remove |
| Playlist | get, fans, tracks, radio, update, delete, mark_seen, add_tracks, reorder_tracks, remove_tracks, favorites add/remove |
| Podcast / Episode | get, episodes, bookmark get/set/remove, favorites add/remove |
| User | get/me, albums, artists, tracks, playlists, podcasts, radios, followings, followers, flow, history, personal_songs, charts_*, recommendations/*, permissions, options, create_playlist, follow/unfollow, add_notification |
| Search | all, tracks, albums, artists, playlists, podcasts, radios, users, advanced(...) field search, history |
| Chart | get (+ genre charts), tracks, albums, artists, playlists, podcasts |
| Editorial | get/list, selection, charts, releases |
| Genre | get/list, artists, podcasts, radios |
| Radio | get/list, genres, top, tracks, lists, favorites add/remove |
| Infos / Options | get |
| oEmbed | get (widget metadata for public Deezer URLs) |
Advanced search example:
page = client.search.advanced("search", artist="Aloe Blacc", track="I Need A Dollar")
page = client.search.tracks("eminem", strict=True, order="RANKING", limit=10)
Pagination:
page = client.playlist.tracks(908622995, index=0, limit=10)
print(page.total)
for track in page.iter_all_items(): # walks every page via `next`
...
Rate limiting:
# default: 50 requests / 5 s + retries on quota (code 4) / busy (code 700)
client = DeezerClient()
# opt out (you run your own throttling)
client = DeezerClient(rate_limit=False)
# custom budget
from deezify.ratelimit import SyncRateLimiter
client = DeezerClient(rate_limit=SyncRateLimiter(max_calls=10, period=5.0))
Typed responses:
High-level shortcuts (same names on the async client with await):
client.find_track("Daft Punk", limit=5) # plain lists, no paging needed
client.best_artist_match("Daft Punk") # first hit or None
client.top_tracks(limit=10) # global charts
client.genres(limit=10) # genre list
client.album_tracks(302127) # every album track
client.playlist_all_tracks(908622995) # walks all pages
client.full_track(3135556) # track + full album + artist
client.track_preview_url(3135556) # 30s mp3 or None
client.my_playlists() # needs access token
Enums (all str-compatible — plain strings keep working too):
from deezify import SearchOrder, Permission, RecommendationKind
client.search.tracks("eminem", order=SearchOrder.RANKING)
client.search.tracks("eminem", order="RANKING") # same thing
client.user.recommendations("me", RecommendationKind.TRACKS)
authorization_url(APP_ID, REDIRECT, perms=[Permission.EMAIL])
from deezify import Track
from deezify.types import Chart, Playlist
track: Track = client.track.get(3135556)
bundle: Chart = client.chart.get()
top_track = client.artist.top(27, limit=1)[0] # inferred as Track
Raw escape hatch for anything new/experimental:
client.raw("GET", "track/3135556")
Error handling
from deezify import DeezerAPIError, DeezerTransportError
try:
client.track.get(0)
except DeezerAPIError as e:
print(e.code, e.type, e.message) # e.g. 800 DataException ...
except DeezerTransportError as e:
print("network problem:", e)
Documented codes: 4 quota, 100 items limit, 200 permission,
300 bad token, 500/501 parameters, 600 bad query, 700 busy,
800 not found, 901 individual-account restriction.
Docs & links
- API reference: https://developers.deezer.com/api
- OAuth: https://developers.deezer.com/api/oauth
- Permissions: https://developers.deezer.com/api/permissions
- Errors: https://developers.deezer.com/api/errors
License
MIT
Metadata
Release files for deezify 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| deezify-1.0.0.tar.gz | 39.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| deezify-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 77.7 kB
Release files / deezify-1.0.0.tar.gz
| Download URL | deezify-1.0.0.tar.gz |
|---|---|
| Size | 39.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4b7fcd00ff439219b72f19d4a79563114cdc8b4ce5303f80d51aafe5bcb0793a
|
|
BLAKE2b-256 checksum How to use checksums |
3db7ae08c0b566323b69f0fa0f4ef014da670d3d83b0be08a2bf1c274f70f082
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Release files / deezify-1.0.0-py3-none-any.whl
| Download URL | deezify-1.0.0-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4c9c57dbd76a1d6957337680a0ebeb167f9cb819d33c050d3f723183bcbf33d5
|
|
BLAKE2b-256 checksum How to use checksums |
999a90124aca9c9ca22d92b25902b50ffca46ed0a9bed760dac23dc83e56f4f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|