Search by

calliostro / spotify-client

calliostro

Lightweight Spotify Web API client for PHP 8.1+ with modern developer comfort โ€” Clean parameter API, two-tier architecture, and minimal dependencies

Package info

github.com/calliostro/spotify-client

pkg:composer/calliostro/spotify-client

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-09-15 12:10 UTC

This package is auto-updated.

Last update: 2026-09-15 12:23:40 UTC


README

Package Version Total Downloads License PHP Version Guzzle CI Code Coverage PHPStan Level Code Style

๐Ÿš€ MINIMAL YET POWERFUL! Focused, lightweight Spotify Web API client โ€” as compact as possible while maintaining modern PHP comfort and clean APIs.

๐Ÿ“ฆ Installation

composer require calliostro/spotify-client

๐Ÿ”‘ Do You Need to Register?

Yes, Spotify requires all Web API applications to be registered:

  1. Create a free developer account and app in the Spotify Developer Dashboard.
  2. Obtain your Client ID and Client Secret.
  3. Configure Redirect URIs (required for User Authentication / OAuth): In your app settings, add your callback URL (e.g., https://myapp.example.com/callback.php). Note: Spotify requires HTTPS unless using loopback IP addresses (http://127.0.0.1:PORT/callback.php or http://[::1]:PORT/callback.php; http://localhost is not permitted).

Which flow do you need?

  • Client Credentials Flow (Server/CLI/Background Workers):
    • Requires: Client ID + Client Secret.
    • For: Searching the catalog, browsing public artists, albums, tracks, playlists, audio features, and categories.
    • No user login prompt required.
  • Authorization Code Flow (User Authentication):
    • Requires: Client ID + Client Secret + user authorization code / tokens.
    • For: Private user playlists, library, player controls, currently playing track, user profile.

๐Ÿš€ Quick Start

1. Server / CLI / Public Catalog Search (Client Credentials Flow)

use Calliostro\Spotify\SpotifyClientFactory;

$spotify = SpotifyClientFactory::createWithCredentials(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret'
);

// Get artist details
$artist = $spotify->getArtist('4Z8W4fKeB5YxbusRsdQVPb'); // Radiohead
echo $artist['name']; // "Radiohead"

// Traditional positional parameters
$albums = $spotify->getArtistAlbums('4Z8W4fKeB5YxbusRsdQVPb', ['album'], 'US', 10);

// Modern PHP 8+ named parameters
$searchResults = $spotify->search(
    query: 'OK Computer',
    type: 'album',
    limit: 5,
    market: 'US'
);

$album = $spotify->getAlbum(
    albumId: '6400dqrMfE4FTGMxS5neUM',
    market: 'US'
);

Note

Spotify apps in default Development Mode have full access to catalog search, artists, albums, tracks, and user authorization flows. Note that endpoints such as /artists/{id}/top-tracks and /artists/{id}/related-artists are restricted by Spotify to apps in Extended Quota Mode.

2. User Authentication (Authorization Code Flow with Refresh Token)

use Calliostro\Spotify\SpotifyClientFactory;

$spotify = SpotifyClientFactory::createWithUserAuth(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    accessToken: $userAccessToken,
    refreshToken: $userRefreshToken
);

// Access private user data
$me = $spotify->getCurrentUser();
echo "Hello, " . $me['display_name'];

3. Direct Access with Pre-existing Token

use Calliostro\Spotify\SpotifyClientFactory;

$spotify = SpotifyClientFactory::createWithAccessToken('your-active-access-token');

$album = $spotify->getAlbum('6400dqrMfE4FTGMxS5neUM');

๐ŸŒ Accessing ANY Endpoint (The Generic HTTP Engine)

To provide maximum flexibility while keeping the codebase lightweight and focused, calliostro/spotify-client employs a two-tier architecture:

In addition to convenient catalog methods, the low-level generic HTTP engine gives you direct access to 100% of the Spotify Web API on day one:

// GET any endpoint (automatic Bearer auth, query string formatting, JSON deserialization)
$queue = $spotify->get('/me/player/queue');
$genres = $spotify->get('/recommendations/available-genre-seeds');

// POST requests
$playlist = $spotify->post("/users/{$userId}/playlists", [
    'name' => 'My New Playlist',
    'public' => false,
    'description' => 'Created via calliostro/spotify-client'
]);

// PUT requests
$spotify->put('/me/player/play', [
    'uris' => ['spotify:track:4cOdK2wGLETKBW3PvgPWqT']
]);

// DELETE requests
$spotify->delete('/me/player/repeat', [
    'state' => 'off'
]);

// Generic request method
$response = $spotify->request('GET', 'me/top/artists', [
    'query' => ['time_range' => 'long_term', 'limit' => 10]
]);

๐Ÿ”„ Automatic Token & Rate Limit Handling

Built specifically for high-reliability CLI commands, background workers, and long-running daemons:

1. Proactive Token Refresh & 401 Self-Healing

  • Spotify tokens expire after 1 hour (3,600 seconds).
  • The client monitors expiration timestamps and proactively refreshes the token 5 minutes (300s) before it expires.
  • If a token is revoked or invalidated mid-flight causing an HTTP 401 Unauthorized, the client automatically refreshes the token and retries the request transparently once before raising an AuthenticationException.

2. Automatic HTTP 429 Rate Limit Backoff

  • When hitting Spotify API rate limits, Spotify provides a Retry-After header indicating how many seconds to wait.
  • By default (auto_retry => true, max_retries => 3), the client respects the backoff period, sleeps, and retries automatically without crashing your pipeline.
  • When retries are exhausted or disabled, a RateLimitException is thrown, exposing $e->getRetryAfter().
use Calliostro\Spotify\SpotifyClientFactory;
use Calliostro\Spotify\Exception\RateLimitException;

$spotify = SpotifyClientFactory::createWithCredentials('client-id', 'client-secret', [
    'auto_retry' => true,   // Automatically wait and retry on 429 (default: true)
    'max_retries' => 5,     // Maximum number of retry attempts (default: 3)
]);

try {
    $data = $spotify->getArtist('4Z8W4fKeB5YxbusRsdQVPb');
} catch (RateLimitException $e) {
    echo "Spotify rate limit exceeded. Retry after {$e->getRetryAfter()} seconds.";
}

โœจ Key Features

  • Two-Tier Architecture โ€“ Generic HTTP engine (get, post, put, delete) covering 100% of the API, alongside high-level catalog convenience methods.
  • Resilient Token Lifecycle โ€“ Proactive 5-minute pre-refresh and automatic 401 retry for both Client Credentials and Refresh Token flows.
  • Built-in Rate Limiting โ€“ Automatic HTTP 429 retry respecting the Retry-After header.
  • Clean Parameter API โ€“ Full support for PHP 8 named parameters and strict types.
  • Lightweight Focus โ€“ Minimal footprint with only essential dependencies (Guzzle 7 or 8).
  • Type-Safe Exceptions โ€“ Distinct exceptions: AuthenticationException, RateLimitException, NotFoundException, ValidationException, and SpotifyException.
  • Modern PHP Comfort โ€“ Full IDE auto-completion, PHPStan Level 8 static analysis, and PSR-12 compliant.
  • Performance โ€“ In-memory token caching and lazy-loaded configuration singleton.
  • Battle-Tested โ€“ 100% unit test coverage with MockHandler.

๐ŸŽต Catalog Convenience Methods

Method Description
search(query, type, limit, offset, market, includeExternal) Search artists, albums, tracks, etc.
getArtist(artistId) Get artist profile, genres, popularity, and images
getArtistAlbums(artistId, includeGroups, market, limit, offset) Get artist discography and releases
getArtistTopTracks(artistId, market)* Get artist top 10 tracks by market
getArtistRelatedArtists(artistId)* Get artists similar to a given artist
getAlbum(albumId, market) Get album details, label, and release date
getAlbumTracks(albumId, market, limit, offset) Get tracks for a specific album
getTrack(trackId, market) Get track details, duration, and popularity
getTracks(trackIds, market) Get multiple tracks in a single request (up to 50)
getCurrentUser() Get current authorized user's profile
getUserProfile(userId) Get public profile for any user

*Note: Endpoints marked with * require Spotify Extended Quota Mode for newly created apps.
Remember: Any other Spotify endpoint can be called instantly using $spotify->get(), $spotify->post(), $spotify->put(), or $spotify->delete()!

๐Ÿ“‹ Requirements

  • PHP ^8.1
  • guzzlehttp/guzzle ^7.0 || ^8.0

โš™๏ธ Configuration

Simple (Works out of the box)

use Calliostro\Spotify\SpotifyClientFactory;

$spotify = SpotifyClientFactory::createWithCredentials('client-id', 'client-secret');

Advanced (Custom Guzzle handler, timeouts, headers)

use Calliostro\Spotify\SpotifyClientFactory;

$spotify = SpotifyClientFactory::createWithCredentials('client-id', 'client-secret', [
    'timeout' => 15,
    'headers' => [
        'User-Agent' => 'MyMusicApp/1.0 (+https://myapp.example.com)',
    ],
    'auto_retry' => true,
    'max_retries' => 3,
]);

๐Ÿ” Authentication & Complete OAuth Flow Example

Quick Reference

What you want to do Method What you need
Public music search, artists, albums, tracks createWithCredentials() Client ID + Client Secret
Background worker / CLI tool createWithCredentials() Client ID + Client Secret
Direct calls with existing token createWithAccessToken() Access token
User library, playlists, playback createWithUserAuth() Client ID + Secret + Access & Refresh Tokens

Complete Authorization Code Flow

Important

Registering your Redirect URI in Spotify Dashboard: You must register the exact Redirect URI in your app settings in the Spotify Developer Dashboard under App Settings โ†’ Redirect URIs.

  • Production: Must use HTTPS (e.g., https://myapp.example.com/callback.php).
  • Local Development: Spotify permits HTTP only for explicit loopback IP addresses (e.g., http://127.0.0.1:8080/callback.php or http://[::1]:8080/callback.php). http://localhost is strictly rejected by Spotify.

Step 1: authorize.php โ€“ Redirect user to Spotify

<?php

use Calliostro\Spotify\AuthHelper;

$auth = new AuthHelper('your-client-id', 'your-client-secret');

$authorizeUrl = $auth->getAuthorizationUrl(
    redirectUri: 'https://myapp.example.com/callback.php',
    scopes: ['user-read-private', 'user-read-email', 'playlist-read-private'],
    state: 'secure-random-state',
    showDialog: false
);

header('Location: ' . $authorizeUrl);
exit;

Step 2: callback.php โ€“ Exchange code for tokens

<?php

require __DIR__ . '/vendor/autoload.php';

use Calliostro\Spotify\AuthHelper;
use Calliostro\Spotify\SpotifyClientFactory;

$code = $_GET['code'] ?? null;
if (!$code) {
    exit('Authorization failed');
}

$auth = new AuthHelper('your-client-id', 'your-client-secret');
$tokens = $auth->requestAccessToken($code, 'https://myapp.example.com/callback.php');

$accessToken = $tokens['access_token'];
$refreshToken = $tokens['refresh_token'];
$expiresIn = $tokens['expires_in'];

// Save $refreshToken in your database for future sessions...

// Create client with user auth
$spotify = SpotifyClientFactory::createWithUserAuth(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    accessToken: $accessToken,
    refreshToken: $refreshToken
);

$user = $spotify->getCurrentUser();
echo "Welcome, " . htmlspecialchars($user['display_name']);

๐Ÿงช Development & Testing Guide

See DEVELOPMENT.md for detailed setup instructions, test suite commands, static analysis, and contribution guidelines.

๐Ÿค Contributing

Contributions are welcome! Please ensure all tests pass and coding standards are maintained:

composer cs-fix
composer analyse
composer test

๐Ÿ“„ License

MIT License โ€“ see the LICENSE file for details.

โš–๏ธ Disclaimer

Spotify is a registered trademark of Spotify AB. This project is an independent, unofficial open-source library and is not affiliated with, endorsed by, or sponsored by Spotify AB.

๐Ÿ™ Acknowledgments

โญ Star this repo if you find it useful!