Search by

A small PHP client for the RadioAPI Management, Now Playing, and Stream Router APIs.

0.0.2 2026-09-15 22:43 UTC

This package is not auto-updated.

Last update: 2026-09-16 17:21:24 UTC


README

A small PHP client for RadioAPI. It covers station management, public and private Now Playing requests, and Stream Router routes.

Install

composer require radioapi/php

The package requires PHP 8.2+ and ext-json. It uses Guzzle's ClientInterface, so you can inject your own configured HTTP client.

To publish it, release the contents of this package/ directory as the radioapi/php repository, tag a version such as v1.0.0, and submit that repository to Packagist. Composer will then resolve the command above.

Start here

Create a client with an API key for the Management API. Pass the root URL of your RadioAPI app, without /api/v1.

use RadioApi\Client;

$radio = new Client(
    baseUrl: 'https://radioapi.example.com',
    apiKey: 'radio_live_YOUR_API_KEY',
);

The base URL comes first so the simplest setup is also clear when using positional arguments:

$radio = Client::make('https://radioapi.example.com', 'radio_live_YOUR_API_KEY');

Inject a configured Guzzle client only when you need custom middleware, retries, timeouts, or a test client:

$radio = Client::make('https://radioapi.example.com', 'radio_live_YOUR_API_KEY', $guzzle);

For public Now Playing, use a client without an API key and the same API base URL:

$radio = new Client(
    apiKey: null,
    baseUrl: 'https://radioapi.example.com',
);

Stations

$station = $radio->stations()->create([
    'name' => 'Chillwave Radio',
    'stream_url' => 'https://stream.example.com/live.mp3',
    'stream_metadata_provider' => 'azuracast',
    'stream_metadata_settings' => [
        'url' => 'https://station.example.com/api/nowplaying/chillwave',
        'genre' => 'Electronic',
        'language' => 'fr',
    ],
    'music_provider' => 'auto',
    'nowplaying_access' => 'public',
    'nowplaying_history_enabled' => true,
]);

echo $station['uuid'];

The supported stream metadata providers are jcplayer (generic/ICY), azuracast, radioking, and live365. AzuraCast, RadioKing, and Live365 require stream_metadata_settings.url. When music enrichment is enabled, stream_metadata_settings.language sets the ISO 639-1 enrichment language and defaults to en; the API also accepts locale as an input alias.

$page = $radio->stations()->list([
    'status' => 'active',
    'per_page' => 25,
]);

$station = $radio->stations()->find('STATION_UUID');

$station = $radio->stations()->update('STATION_UUID', [
    'nowplaying_access' => 'private',
]);

// Disables the station. It does not hard-delete it.
$radio->stations()->delete('STATION_UUID');

list() returns the API pagination object with data, links, and meta. create(), find(), and update() return the unwrapped resource from data.

For a fluent alternative to payload arrays, use a station builder:

$station = $radio->stations()->builder()
    ->name('Chillwave Radio')
    ->streamUrl('https://stream.example.com/live.mp3')
    ->streamMetadataProvider('azuracast')
    ->streamMetadataUrl('https://station.example.com/api/nowplaying/chillwave')
    ->streamMetadataGenre('Electronic')
    ->language('fr')
    ->nowPlayingAccess('public')
    ->nowPlayingHistoryEnabled()
    ->create();

$station = $radio->stations()->builder()
    ->nowPlayingAccess('private')
    ->update('STATION_UUID');

Station list filters can also be built fluently:

$page = $radio->stations()->query()
    ->status('active')
    ->sortBy('name')
    ->descending()
    ->perPage(25)
    ->get();

Now Playing

Use the same authenticated client for a private station. Public stations do not need an API key:

$nowPlaying = $radio->nowPlaying('STATION_UUID');

echo $nowPlaying['artist'].' — '.$nowPlaying['song'];
use RadioApi\Client;

$publicRadio = Client::forPublicNowPlaying(
    'https://nowplaying.radioapi.example.com',
);

$nowPlaying = $publicRadio->nowPlaying('STATION_UUID');

Now Playing returns a top-level metadata object. The upstream stream field is never exposed. The payload can include name, bitrate, format, artist, song, album, genre, artwork, year, duration, elapsed, remaining, time, lyrics, explicit, songFound, and metadataFound.

When Track History is enabled for the station and the provider has history available, the response also has a history array. Treat provider metadata as optional: an unavailable field is usually an empty string or zero value.

Stream Router

Create a public route that follows a station’s current stream URL:

$route = $radio->streamRouter()->create([
    'station_uuid' => 'STATION_UUID',
    'slug' => 'chillwave',
    'redirect_status_code' => 307,
]);

echo $route['url'];

Or route straight to an external stream without a station:

$route = $radio->streamRouter()->create([
    'target_url' => 'https://cdn.example.com/chillwave.mp3',
    'slug' => 'chillwave-direct',
]);
$routes = $radio->streamRouter()->list(['status' => 'active']);
$route = $radio->streamRouter()->find('ROUTE_UUID');

$route = $radio->streamRouter()->update('ROUTE_UUID', [
    'is_active' => false,
]);

// Disables the route. It does not hard-delete it.
$radio->streamRouter()->delete('ROUTE_UUID');

Use exactly one of station_uuid or target_url when creating or changing a route. Valid redirect_status_code values are 302 and 307.

The equivalent fluent route API is:

$route = $radio->streamRouter()->builder()
    ->stationUuid('STATION_UUID')
    ->slug('chillwave')
    ->redirectStatusCode(307)
    ->create();

$route = $radio->streamRouter()->builder()
    ->targetUrl('https://cdn.example.com/chillwave.mp3')
    ->slug('chillwave-direct')
    ->create();

Calling stationUuid() removes a previously set targetUrl() and vice versa, so a builder always sends only one route destination.

Errors

All non-2xx responses throw RadioApi\Exceptions\ApiException. It carries the HTTP status, RadioAPI error code, response payload, and response headers.

use RadioApi\Exceptions\ApiException;

try {
    $radio->stations()->create([
        'name' => 'Missing stream URL',
    ]);
} catch (ApiException $exception) {
    if ($exception->errorCode === 'validation_error') {
        $fields = $exception->response['error']['fields'] ?? [];
    }
}

Malformed or empty JSON responses throw RadioApi\Exceptions\InvalidResponseException. Network failures throw RadioApi\Exceptions\TransportException with the original Guzzle exception attached as the previous exception.

Test the package

composer install
composer test

License

MIT. See LICENSE.