Public API

Integration guide for BoxRadio's public read-only web endpoints. No authentication required.

Looking for direct stream URLs? Browse stream links

Overview

The BoxRadio API is a JSON REST API served on a dedicated API host. There is no /api path prefix — resources live at the root, for example /radios and /genres.

AudienceEndpointsAuthentication
Public (web)Radios, genres, single-station metadataNone

Response format: Successful responses use Content-Type: application/json. Collection and single-resource responses wrap the payload in a top-level data key.

Web clients should pass platform=web on list endpoints.


Base URL

EnvironmentBase URL
Productionhttps://boxradioedge.radioapi.me

All paths below are relative to the base URL. Example: list radios → GET https://boxradioedge.radioapi.me/radios?platform=web.

The API host only serves JSON API routes. Browser requests to the API domain always negotiate JSON responses (including 404 errors).


Request conventions

HeaderValueWhen
Acceptapplication/jsonRecommended on every request

Query parameters

  • Booleans: Pass 1, true, or featured=1 — all are treated as true.

Identifiers in URLs

Path parameters such as {radio} and {genre} accept either:

  • The resource UUID, or
  • The resource slug (URL-friendly string, e.g. box-radio).

Pagination

List endpoints return the full result set in one response. There is no cursor or page parameter.

Caching recommendations

EndpointSuggested TTL
GET /radios, GET /genres5–15 minutes (or until user refresh)
GET /radios/{id}Same as list
GET /metadata/{radio}15–30 seconds (server caches ~30s for proxied metadata)

Public endpoints

List radios

Returns radio stations for web, optionally filtered by featured flag or search query.

GET /radios?platform=web

Query parameters

ParameterTypeRequiredDescription
platformwebYesScopes results to web
featuredbooleanNoOnly stations featured on web
qstringNoCase-sensitive substring search on name, description, and slug

Behaviour notes

  • Results are sorted alphabetically by name.

Example request

curl -sS -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/radios?platform=web"
curl -sS -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/radios?platform=web&q=rock"

Example response — 200 OK

{
  "data": [
    {
      "id": "9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
      "name": "Box Radio",
      "slug": "box-radio",
      "image": "https://ik.imagekit.io/boxradio/radios/box-radio.jpg",
      "tag": "Pop",
      "metadata": {
        "static": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f.json",
        "external": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
        "internal": "https://boxradioedge.radioapi.me/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f"
      },
      "streams": [
        {
          "name": "Main Stream",
          "url": "https://stream.example.com/live",
          "type": "icecast",
          "is_default": true
        }
      ]
    }
  ]
}

JavaScript example

const baseUrl = 'https://boxradioedge.radioapi.me';

const res = await fetch(
  `${baseUrl}/radios?platform=web`,
  { headers: { Accept: 'application/json' } }
);

if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { data: radios } = await res.json();

Get radio

Returns a single station. Includes description (not present on list items).

GET /radios/{slug_or_uuid}

Path parameters

ParameterDescription
slug_or_uuidStation UUID or slug

Example request

curl -sS -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/radios/box-radio"

Example response — 200 OK

{
  "data": {
    "id": "9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
    "name": "Box Radio",
    "slug": "box-radio",
    "description": "Your home for pop hits and live shows.",
    "image": "https://ik.imagekit.io/boxradio/radios/box-radio.jpg",
    "tag": "Pop",
    "metadata": {
      "static": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f.json",
      "external": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
      "internal": "https://boxradioedge.radioapi.me/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f"
    },
    "streams": [
      {
        "name": "Main Stream",
        "url": "https://stream.example.com/live",
        "type": "icecast",
        "is_default": true
      }
    ]
  }
}

Example response — 404 Not Found

{
  "message": "Not found."
}

Prefer matching UI routes to slug for shareable URLs; use id (UUID) as the stable primary key in local storage and analytics.


List genres

Returns genres enabled for web.

GET /genres?platform=web

Query parameters

ParameterTypeRequiredDescription
platformwebYesReturns genres enabled for web

Example request

curl -sS -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/genres?platform=web"

Example response — 200 OK

{
  "data": [
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "name": "Pop",
      "slug": "pop",
      "description": "Chart hits and mainstream pop.",
      "image": "https://ik.imagekit.io/boxradio/genres/pop.jpg",
      "color": "#FF5733"
    }
  ]
}

The radios array is not included on the list endpoint. Load genre detail for station lists inside a genre.


Get genre

Returns one genre with its related web radio stations.

GET /genres/{slug_or_uuid}?platform=web

Path parameters

ParameterDescription
slug_or_uuidGenre UUID (id) or slug

Query parameters

ParameterTypeRequiredDescription
platformwebYesFilter related radios to those enabled on web
featuredbooleanNoWhen true, only radios marked featured in this genre

Related radios are ordered by featured-in-genre first, then alphabetically by station name.

Example request

curl -sS -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/genres/pop?platform=web"

Example response — 200 OK

{
  "data": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "name": "Pop",
    "slug": "pop",
    "description": "Chart hits and mainstream pop.",
    "image": "https://ik.imagekit.io/boxradio/genres/pop.jpg",
    "color": "#FF5733",
    "radios": [
      {
        "id": "9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
        "name": "Box Radio",
        "slug": "box-radio",
        "image": "https://ik.imagekit.io/boxradio/radios/box-radio.jpg",
        "tag": "Pop",
        "metadata": {
          "static": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f.json",
          "external": "https://openapi.streamafrica.cloud/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f",
          "internal": "https://boxradioedge.radioapi.me/metadata/9b8d7e6f-5a4b-3c2d-1e0f-9a8b7c6d5e4f"
        },
        "streams": [
          {
            "name": "Main Stream",
            "url": "https://stream.example.com/live",
            "type": "icecast",
            "is_default": true
          }
        ]
      }
    ]
  }
}

Get station metadata

Returns now playing information for one station.

GET /metadata/{slug_or_uuid}

Path parameters

ParameterDescription
slug_or_uuidStation UUID or slug

Query parameters

ParameterTypeDescription
historyintegerWhen set (e.g. 1), include recent track history (forwarded on redirect)
languagestringPreferred metadata language
servicestringOverride metadata service detection
genrestringGenre hint for metadata lookup

Response modes

ConditionHTTPWhat the client receives
Station has no metadata source configured404JSON error message
Station is linked to RadioAPI UUID302Redirect to external metadata URL
Otherwise200JSON body from metadata proxy

Example request

curl -sS -L -H "Accept: application/json" \
  "https://boxradioedge.radioapi.me/metadata/box-radio?history=1&language=en"

Example response — 200 OK (proxied JSON)

{
  "artist": "Led Zeppelin",
  "title": "Stairway to Heaven",
  "album": "Led Zeppelin IV",
  "artwork": "https://cdn.example.com/artwork/stairway.jpg"
}

Example response — 404 Not Found

{
  "message": "No metadata source configured for this station"
}

Integration tips

  1. Use metadata.external or metadata.static from the radio object when available — fetch RadioAPI directly and skip the redirect round-trip.
  2. Use metadata.internal for a consistent URL per station; enable redirect following in your HTTP client.
  3. Polling — Refresh every 15–30 seconds while playing; back off when paused.
async function fetchNowPlaying(radio) {
  const url = radio.metadata.internal ?? radio.metadata.external;
  if (!url) return null;

  const res = await fetch(url, {
    headers: { Accept: 'application/json' },
    redirect: 'follow',
  });

  if (res.status === 404) return null;
  if (!res.ok) throw new Error(`Metadata HTTP ${res.status}`);
  return res.json();
}

Data shapes

Radio (list)

Used in: GET /radios?platform=web.

FieldTypeNullableDescription
idstring (UUID)NoStable station identifier
namestringNoDisplay name
slugstringNoURL-friendly identifier
imagestring (URL)YesArtwork
tagstringYesDefault genre/tag label
metadataobjectNoSee Metadata links
streamsarrayNoAvailable streams

Radio (detail)

Used in: GET /radios/{id}, genre radios arrays.

Same as the list shape, plus description (string, nullable). List items do not include description.

Stream

FieldTypeDescription
namestringLabel shown in stream picker
urlstringPlayback URL
typestringStream type hint for the player
is_defaultbooleanUse when auto-selecting a stream

Playback tip: Prefer the stream where is_default is true; otherwise use the first item.

FieldTypeDescription
staticstring (URL) | nullRadioAPI metadata JSON
externalstring (URL) | nullRadioAPI metadata endpoint
internalstring (URL) | nullBoxRadio proxy (GET /metadata/{uuid})

Genre

FieldTypeNullableDescription
idstring (UUID)NoGenre identifier
namestringNoDisplay name
slugstringNoURL-friendly identifier
descriptionstringYesLong description
imagestring (URL)YesGenre artwork
colorstringNoHex colour for UI accents
radiosarrayGenre detail only

Error handling

StatusWhen
200Success
302Metadata redirect to RadioAPI (not an error)
404Unknown radio/genre, or metadata not configured
503Metadata provider unreachable or failed

Most errors return:

{
  "message": "Human-readable summary"
}

Recommended handling:

  • 404 → Show “not found” UI; refresh station list
  • 503 → Retry metadata with exponential backoff; show “now playing unavailable”
  • 302 → Follow redirect (or use metadata.external directly)

Integration patterns

  1. GET /radios?platform=web — load the station grid
  2. GET /genres?platform=web — browse categories
  3. Poll GET /metadata/{slug} or use metadata.external while a station is playing

Choosing a metadata URL

metadata.static   → GET JSON file (good for simple polling)
metadata.external → GET live metadata from RadioAPI
metadata.internal → Same data via BoxRadio proxy; handles mixed station configs

Quick reference

MethodPathAuthResponse wrapper
GET/radios?platform=webPublic{ "data": [...] }
GET/radios/{slug_or_uuid}Public{ "data": {...} }
GET/genres?platform=webPublic{ "data": [...] }
GET/genres/{slug_or_uuid}?platform=webPublic{ "data": {...} }
GET/metadata/{slug_or_uuid}PublicJSON or 302