PHPackages                             kemo/beatport-api-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. kemo/beatport-api-client

ActiveLibrary[API Development](/categories/api)

kemo/beatport-api-client
========================

Standalone Beatport API client for PHP

1.0.0(4mo ago)03MITPHPPHP &gt;=8.4CI passing

Since Feb 12Pushed 4mo agoCompare

[ Source](https://github.com/kemo/beatport-api-client)[ Packagist](https://packagist.org/packages/kemo/beatport-api-client)[ Docs](https://github.com/kemo/beatport-api-client)[ RSS](/packages/kemo-beatport-api-client/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (7)Versions (3)Used By (0)

Beatport API Client
===================

[](#beatport-api-client)

[![CI](https://github.com/kemo/beatport-api-client/actions/workflows/ci.yml/badge.svg)](https://github.com/kemo/beatport-api-client/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/fb123ad53babc8120de2c3433d23fcb2d7fd1b9e4f42c355e59aed28fb623cbb/68747470733a2f2f636f6465636f762e696f2f67682f6b656d6f2f62656174706f72742d6170692d636c69656e742f67726170682f62616467652e737667)](https://codecov.io/gh/kemo/beatport-api-client)[![PHPStan level 6](https://camo.githubusercontent.com/bbb4b88ceed026f420c1d76bc64e1ce076ed7382a9f5bac1cd59d85d807e7af4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230362d627269676874677265656e)](https://phpstan.org/)[![PHP 8.4+](https://camo.githubusercontent.com/80c4564163cef31b2a66baaeb95a5bf4a418bcb5242a5ae707b94c2f4811e742/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342532422d626c7565)](https://www.php.net/)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](LICENSE)

A standalone PHP client for the Beatport API. Provides three complementary clients for different access patterns: OAuth API, internal API, and web scraping.

Features
--------

[](#features)

- **OAuth API client** — Authenticated access to Beatport API v4 (library, tracks, search)
- **Internal API client** — Public access to tracks, artists, labels, releases, genres, and charts
- **Scrape client** — Session-based web scraping for library and track data
- **Full auth flow** — OAuth PKCE authorization and username/password login
- **DTOs** — Structured `BeatportTrack` and `LoginResult` objects
- **Domain exceptions** — `AuthenticationException`, `InvalidSessionException`, `SessionExpiredException`

Installation
------------

[](#installation)

```
composer require kemo/beatport-api-client
```

Requires PHP 8.4+ and a PSR-18 compatible HTTP client. The package uses `symfony/http-client-contracts`, so any Symfony HTTP client implementation works:

```
composer require symfony/http-client
```

Usage
-----

[](#usage)

### Internal API Client (No Auth Required)

[](#internal-api-client-no-auth-required)

The `InternalApiClient` accesses Beatport's internal API without authentication:

```
use Kemo\Beatport\InternalApiClient;
use Symfony\Component\HttpClient\HttpClient;

$client = new InternalApiClient(HttpClient::create());

// Tracks
$track = $client->getTrack(123456);
$tracks = $client->getTracks(page: 1, perPage: 25, orderBy: '-publish_date');
$topTracks = $client->getTopTracks(genreId: 1, page: 1, perPage: 100);

// Artists
$artist = $client->getArtist(12345);
$artistTracks = $client->getArtistTopTracks(artistId: 12345, perPage: 10);

// Labels
$label = $client->getLabel(678);
$labelTracks = $client->getLabelTopTracks(labelId: 678, perPage: 10);

// Releases
$release = $client->getRelease(789);

// Genres
$genres = $client->getGenres();
$genre = $client->getGenre(1);
$genreTracks = $client->getGenreTopTracks(genreId: 1, perPage: 10);

// Charts
$chart = $client->getChart(456);
$charts = $client->getCharts(page: 1, perPage: 25);

// Search
$results = $client->search(query: 'Daft Punk', type: 'tracks', page: 1, perPage: 25);
```

### OAuth API Client

[](#oauth-api-client)

The `ApiClient` requires an OAuth access token:

```
use Kemo\Beatport\ApiClient;
use Symfony\Component\HttpClient\HttpClient;

$client = new ApiClient(HttpClient::create(), accessToken: 'your-access-token');

$account = $client->getAccount();
$myTracks = $client->getMyBeatportTracks(perPage: 100);
$track = $client->getTrack(123456);
$results = $client->searchTracks(query: 'Bicep', page: 1, perPage: 25);
$topTracks = $client->getTopTracks(page: 1, perPage: 25);
```

### Authentication

[](#authentication)

#### OAuth PKCE Flow

[](#oauth-pkce-flow)

```
use Kemo\Beatport\AuthClient;
use Symfony\Component\HttpClient\HttpClient;

$auth = new AuthClient(HttpClient::create());

// Step 1: Get authorization URL
$url = $auth->getAuthorizationUrl(
    clientId: 'your-client-id',
    redirectUri: 'https://your-app.com/callback',
    codeChallenge: $challenge,
);

// Step 2: Exchange code for tokens
$tokens = $auth->exchangeCodeForTokens(
    clientId: 'your-client-id',
    redirectUri: 'https://your-app.com/callback',
    code: $authorizationCode,
    codeVerifier: $verifier,
);
// $tokens = ['access_token' => '...', 'refresh_token' => '...', 'expires_in' => 3600]

// Step 3: Refresh when expired
$refreshed = $auth->refreshAccessToken(
    clientId: 'your-client-id',
    refreshToken: $tokens['refresh_token'],
);
```

#### Username/Password Login

[](#usernamepassword-login)

```
use Kemo\Beatport\LoginClient;
use Kemo\Beatport\AuthClient;
use Symfony\Component\HttpClient\HttpClient;

$httpClient = HttpClient::create();
$login = new LoginClient($httpClient, new AuthClient($httpClient));

$result = $login->login(username: 'user@example.com', password: 'password');
// LoginResult with: sessionCookies, username, accessToken, refreshToken, expiresIn, beatportUserId
```

### Scrape Client

[](#scrape-client)

The `ScrapeClient` uses session cookies for web scraping:

```
use Kemo\Beatport\ScrapeClient;
use Symfony\Component\HttpClient\HttpClient;

$scraper = new ScrapeClient(HttpClient::create(), requestDelayUs: 500_000);
$scraper->setSession($sessionCookies);

if ($scraper->isSessionValid()) {
    $tracks = $scraper->getLibraryTracks(page: 1);
    $allTracks = $scraper->getAllLibraryTracks(maxPages: 50);
    $pageCount = $scraper->getLibraryPageCount(maxPages: 50);
    $track = $scraper->getTrack(trackId: 123456, slug: 'track-name');
    $results = $scraper->searchTracks(query: 'Disclosure', page: 1);
}
```

### DTOs

[](#dtos)

#### BeatportTrack

[](#beatporttrack)

```
use Kemo\Beatport\Dto\BeatportTrack;

// From API response
$track = BeatportTrack::fromApiResponse($apiData);

// From scraped data
$track = BeatportTrack::fromScrapedData($scrapedData);

$track->beatportId;  // string
$track->title;       // string
$track->mix;         // ?string
$track->artistName;  // ?string
$track->albumName;   // ?string
$track->durationMs;  // ?int
$track->bpm;         // ?int
$track->musicalKey;  // ?string
$track->genre;       // ?string
$track->label;       // ?string
```

### Exception Handling

[](#exception-handling)

```
use Kemo\Beatport\Exception\AuthenticationException;
use Kemo\Beatport\Exception\InvalidSessionException;
use Kemo\Beatport\Exception\SessionExpiredException;

try {
    $login->login('user@example.com', 'wrong-password');
} catch (AuthenticationException $e) {
    // Authentication failed
}

try {
    $scraper->setSession('invalid-cookies');
} catch (InvalidSessionException $e) {
    // Invalid session cookies
}

try {
    $scraper->getLibraryTracks();
} catch (SessionExpiredException $e) {
    // Session has expired
}
```

Architecture
------------

[](#architecture)

```
src/
├── AbstractApiClient.php      # Shared HTTP client base class
├── ApiClient.php              # OAuth API v4 client
├── InternalApiClient.php      # Internal API client (no auth)
├── ScrapeClient.php           # Web scraping client
├── AuthClient.php             # OAuth PKCE flow
├── LoginClient.php            # Username/password login
├── Beatport.php               # URL constants
├── Dto/
│   ├── BeatportTrack.php      # Track data transfer object
│   ├── LoginResult.php        # Login result DTO
│   └── TrackTitleParser.php   # Title/mix parser utility
├── Exception/
│   ├── AuthenticationException.php
│   ├── InvalidSessionException.php
│   └── SessionExpiredException.php
└── Util/
    └── SlugHelper.php         # URL slug generation

```

Development
-----------

[](#development)

```
# Install dependencies
composer install

# Run tests
composer test

# Run tests with coverage
composer test:coverage

# Static analysis
composer phpstan

# Check code style
composer cs:check

# Fix code style
composer cs:fix

# Full QA pipeline (cs:check + phpstan + test)
composer qa
```

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

Contributing
------------

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md).

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md).

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance74

Regular maintenance activity

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

142d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7ca3781cebcc86df44893a47f55d55844817d997a5db0f476850d08826c7cefd?d=identicon)[kemo](/maintainers/kemo)

---

Top Contributors

[![kemo](https://avatars.githubusercontent.com/u/100160?v=4)](https://github.com/kemo "kemo (6 commits)")

---

Tags

apiclientscrapermusicbeatportdj

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/kemo-beatport-api-client/health.svg)

```
[![Health](https://phpackages.com/badges/kemo-beatport-api-client/health.svg)](https://phpackages.com/packages/kemo-beatport-api-client)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.6M3.1k](/packages/craftcms-cms)[binarytorch/larecipe

Generate gorgeous recipes for your Laravel applications using MarkDown

2.5k2.9M17](/packages/binarytorch-larecipe)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M204](/packages/sulu-sulu)[drupal/drupal-extension

Drupal extension for Behat

22215.7M173](/packages/drupal-drupal-extension)[drupal/core-dev

require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.

2022.6M343](/packages/drupal-core-dev)[blackfire/player

A powerful web crawler and web scraper with Blackfire support

49617.1k](/packages/blackfire-player)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
