Radio Cult Online Radio API Reference

Introduction

Looking to integrate a powerful radio API for developers into your online radio station? The Radio Cult API provides comprehensive endpoints and workflows for building custom radio applications, automating broadcasting tasks, and creating seamless listener experiences.

Our radio API for developers follows REST architecture principles, exposing both read and write endpoints that enable you to power websites, automate workflows, and build custom integrations. Whether you're developing a new website, mobile app or automated scheduling workflows our API provides the flexibility developers need.

All endpoints return clean JSON-encoded responses with standard HTTP response codes, making integration straightforward for any development stack. Our API workflows support everything from simple player embeds to complex automation systems.

Authentication uses secure API keys that prove access permissions. Follow standard security protocols with your API key, which can be regenerated anytime to maintain security integrity.

Not a developer?

You can easily integrate Radio Cult functionality into your site using our range of embeds - such as our chat rooms, weekly schedule and player components.

Don't have an account yet?

You need to create a Radio Cult account before you can power your station with our APIs. Go to our sign up page to get started!

Why the Radio Cult API?

If you're already managing your internert radio station data through Radio Cult, why take the extra step of using an external Content Management System (CMS) when you can just use Radio Cult as a CMS?

Not only can you manage all your data on the Radio Cult platform - like your artist profiles and schedules - you can also fetch this data to display on your site. Radio Cult is the one-stop shop for your station.

Getting started

To get started using our API you need to create an API key first. The API key allows you to access all our APIs by proving you are who you say you are. Afterall, we only want you to be able to access your station data.

Agent skills

Working with an AI coding agent like Claude Code, Codex or Gemini CLI? We publish ready-made agent skills that teach your agent to build against the Radio Cult API correctly: realtime WebSocket updates instead of polling, correct audio element handling, efficient schedule queries with correct timezone handling, safe API key usage and reliable upload workflows.

Using Claude? Download the skill zip. Add it to ~/.claude/skills/ for Claude Code, or upload it as a skill on claude.ai.

Using ChatGPT, Codex, Gemini or another agent? Copy the prompt into your agent's instructions, for example your project's AGENTS.md or GEMINI.md file, a Custom GPT's instructions, or a Gemini Gem.

Custom player skill

Helps your agent build a custom web player for your station: live now-playing metadata over WebSockets, an audio element that always joins at the live edge and disconnects cleanly on pause (keeping your listener analytics accurate), and publishable-key-only authentication.

Schedule and website skill

Helps your agent build your station website from the API: weekly programme grids and schedule pages, artist directory and profile pages, and a recently-played tracks feed. It uses the expand param to hydrate artists and tags in one request only when they are shown, handles UTC to local timezone conversion, renders TipTap descriptions and builds artist pages from slugs.

Media upload skill

Lets your agent upload tracks straight to your media library for you. Tell it "upload this folder to my station" and it validates the files (mp3 or m4a, under 750MB), confirms the list, uploads sequentially with rate-limit awareness and reports the results. Also covers metadata overrides, playlist and tag assignment, and building your own upload automations. Uses your secret key, so it belongs in server-side or CLI workflows. Note that the upload endpoint is disabled by default, please contact us to enable it for your account.

API keys

Generating an API key

To generate an API key for your station, simply head over to the API key settings page. On this page you will be able to generate new secret and publishable API keys. You can delete or roll API keys at any point.

Your station ID

You will also be able to find your unique stationId on the API key settings page. You will need to use your stationId to build the correct URLs for our REST API.

Publishable vs secret keys

Public key

Publishable keys are used to access read-only endpoints that return data safe for public display. This means there is limited access if your key gets leaked.

In short, this means you're safe to use your publishable keys on your website.

If you wish to block access in the future then simply delete or roll your publishable key.

A publishable API key should look something like: pk_34c9a89dd5434676972834781b55ad40

Secret key

Secret keys allow access to all API endpoints, including automation endpoints that modify your station's data. For example, uploading media, creating artists and more.

Due to the expanded access of secret keys, you should take precautions to prevent your secret key from being leaked (hence, the wonderfully apt name of a "secret" key).

You will most likely be using your secret key in your backend or as part of a CLI workflow. You should not use your secret key on your website.

If you wish to access read-only data, then you should use a publishable key, which can be safely stored and used in your frontend code.

A secret API key should look something like: sk_34c9a89dd5434676972834781b55ad40s78ahddha6884

Using your API key

Once you have your API key is is simple to use it. Simply include the API key in the x-api-key header on all requests to our API.

The x-api-key header value can be a publishable or a secret key. Use the correct API key for the endpoint in question.

In general, use a publishable API key for all GET requests. Use a secret key for any PUT, POST or DELETE requests.

An example of using your API key
fetch('https://api.radiocult.fm/api/station/:stationId/artists', {
  headers: {
    'x-api-key': <your_api_key_here>,
  },
});

API URL

The URL to use for all API endpoints is https://api.radiocult.fm. Make sure to direct requests there rather than the normal Radio Cult URL.

Radio Cult API URL
'https://api.radiocult.fm'

Automation endpoints

Throughout this reference some endpoints are marked with:Automation . These are the automation endpoints that write to and manage your station's data, such as uploading media, creating artists, and managing playlists, tags and recordings. Access to these endpoints requires a Premium plan or higher.

Read-only endpoints are available on any plan. They include everything you need to build your station's players, websites, schedules and mobile apps, regardless of the plan you are on.

Errors

The Radio Cult API uses conventional HTTP response codes to indicate the success or failure of each request.

In general: response status codes in the 2xx range indicate success. 4xx response codes indicate an error due to invalid information provided to the endpoint (e.g., missing or incorrect parameters). 5xx response codes indicate an error with our servers, and not your request (these are rare, if this does happen then we will have been alerted and on the case but feel free to reach out as well).

We try to be consistent with return values. In the case of an error, every reponse body should be an object containing at least the property success which will be set to false.

Error response
{
    success: false,
    error?: string
}

Rate limiting

To ensure fair usage, we enforce rate limits on key automation endpoints. Limits are applied per station.

There are two layers of protection:

  • Burst limit — prevents a large number of requests being made within a short period (per minute)
  • Daily limit — caps the total number of requests per day

Every response includes headers so you can track your current usage and build smarter retry logic.

Rate limit response headers example
X-RateLimit-Limit-Burst: 20
X-RateLimit-Remaining-Burst: 17
X-RateLimit-Reset-Burst: 1743609600
X-RateLimit-Limit-Daily: 2000
X-RateLimit-Remaining-Daily: 1847
X-RateLimit-Reset-Daily: 1743638400

Handling a 429 response

When a rate limit is exceeded the API returns a 429 Too Many Requests response. The Retry-After header tells you how many seconds to wait before retrying. The response body includes additional detail about which limit was hit.

We recommend implementing exponential backoff in your integration. Monitor the X-RateLimit-Remaining-* headers to slow down proactively before hitting a limit.

429 response body
{
  "success": false,
  "error": "Too Many Requests",
  "limitType": "burst",
  "limit": 20,
  "remaining": 0,
  "retryAfter": 42,
  "resetsAt": "2025-01-01T12:01:00Z"
}

API routes

Below you will find an overview of all the API routes you can query to power your site and internal tools, along with an explanation of the objects and entities returned.

Schedule

The schedule endpoints can be used to work out what is playing on your stream now and what events are scheduled for the future.

You'll generally query the live now endpoint to build custom players and display what is currently being played on your stream. You'll want to use the range endpoint for building Schedule pages, displaying upcoming events for the week.

These endpoints will return Events. The Event object represents an instance of an scheduled event.

Endpoints
GET /api/station/:stationId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>
GET /api/station/:stationId/schedule/live

The Event object

Attributes

idstring

The unique ID of the event

stationIdstring

The unique ID of the station that the event belongs to

titlestring

The title of the event

startDateUtcstring [UTC timestamp]

The start date of the event formatted as a ISO timestamp

endDateUtcstring [UTC timestamp]

The end date of the event formatted as a ISO timestamp

descriptionJSONContent | undefined

The event description represented in TipTap JSON format

durationMinutes (number)

The duration of the event expressed as minutes

timezonestring

The original timezone the event was created in

colorstring | undefined

The color of the event as a hex code

mediastring

The media attached to an event. Media can either be live, a mix or a playlist.

artistIdsArray<string> | undefined

An optional array of the IDs of artists attached to an event

isRecurringboolean

A boolean value indicating whether the event is standalone (i.e. doesn't repeat) or is repeating (i.e. is part of a series of events)

modifiedstring [UTC timestamp]

A UTC timestamp of when the event was last modified/updated.

createdstring [UTC timestamp]

A UTC timestamp of when the event was created.

The event object
{
    id: string;
    stationId: string;
    title: string;
    startDateUtc: string;
    endDateUtc: string;
    description?: JSONContent;
    duration: Minutes;
    timezone: string;
    color?: string;
    artistIds?: string[];
    isRecurring: boolean
    media: 
      | {
        type: 'mix';
        trackId?: string | undefined;
      }
      | {
          type: 'playlist';
          playlistId: string;
        }
      | {
          type: 'live';
        };
}

Retrieve live now

Call the get live now endpoint to return what is currently playing.

This endpoint will return the "status" of your stream and the content being played. The "status" can be one of three things - either:

  1. schedule - which means a scheduled event is playing,
  2. offAir - which means your stream is off air and nothing is playing, or
  3. defaultPlaylist - which means there is no scheduled event and your default playlist is playing.

The content of the stream can be an Event (in the case of a scheduled show), an Off Air enum to indicate the stream is off air or the details associated with your default playlist.

The endpoint also returns:

  • the Metadata of the track details currently being played on the stream. See below for more details on the shape of the Metadata object.
  • the LiveMusicRecognition of the track currently detected to be playing on the stream. This object will only be defined if your Radio Cult account has the 24/7 Music Recognition add-on. See below for more details on the shape of the LiveMusicRecognition object.
Endpoint
GET /api/station/:stationId/schedule/live
Response
{
  success: true;
  result:
    | { 
        status: 'schedule'; 
        content: Event; 
        metadata: Metadata; 
        musicRecognition?: LiveMusicRecognition; 
      }
    | { 
        status: 'offAir'; 
        content: 'Off Air'; 
        metadata: Metadata;
        musicRecognition?: LiveMusicRecognition; 
      }
    | {
        status: 'defaultPlaylist';
        content: {
          name: string;
          numberOfSongs: number;
          duration: Minutes;
        };
        metadata: Metadata;
        musicRecognition?: LiveMusicRecognition; 
  };
}

Real-time updates

For live updates on your station's metadata, we recommend using WebSockets.

With WebSockets, we send updates immediately when the metadata changes, ensuring the most up-to-date data. Using Websockets puts less load on our servers and results in a better experience for your listeners.

Unlike polling the "live now" endpoint every minute, which may result in a few seconds of delay, WebSockets provide instant updates. This is why all of our player embeds are powered by WebSockets.

Our WebSockets use Socket.IO, so you'll need the client version of Socket.IO to connect.

To authenticate, include your API key in the auth section when establishing the connection.

All metadata updates will be delivered under the player-metadata event.

We've included example code showing you how to connect and start consuming Websocket events.

Example code
import SocketIo from 'socket.io-client';

const io = SocketIo('https://api.radiocult.fm', {
  auth: {
    'x-api-key': <your API key here>,
  },
  transports: ['websocket'],
  query: {
    stationId: <your station ID here>,
  },
});

io.on('player-metadata', ({ status, content, metadata }) => {
  // Process the results here
});

The Metadata object

titlestring

The title of the current song (or, potentially, the metadata pushed via your live streaming client)

filenamestring

The filename of the current song

durationnumber (Seconds)

The duration of the current song in seconds

albumstring | undefined

The album of the current song

artiststring | undefined

The artist of the current song

playoutStartUnixTimestampnumber (unix timestamp)

The unix timestamp of when the current song started playing

playoutStartIsoTimestampstring (ISO timestamp)

The ISO timestamp of when the current song started playing

artworkmap | undefined

The artwork for the current song. If no artwork has been uploaded then this may be undefined. Once artwork has been uploaded it is automatically resized. The resizing happens asynchronously. As such, there is a possibility that any of the resize values may be undefined for a few seconds after the image has been uploaded. The time window is so small that you will be very unlikely to ever run into this.

notesstring | undefined

The notes of the current song

Metadata
type Metadata = {
  title: string;
  filename: string;
  duration: Seconds;
  album: string | undefined;
  artist: string | undefined;
  playoutStartUnixTimestamp: number;
  playoutStartIsoTimestamp: string;
  artwork: {
    original?: string;
    default?: string;
    '32x32'?: string;
    '64x64'?: string;
    '128x128'?: string;
    '256x256'?: string;
    '512x512'?: string;
  } | undefined;
  notes: string | undefined;
}

The LiveMusicRecognition object

status'match' | 'noMatch'

The status of the live music recognition indicating whether a song has been matched to what is currently being broadcast from the stream.

titlestring

The title of the currently matched song

durationnumber (Seconds) | 'unknown'

The duration of the currently matched song in seconds

albumstring | undefined | null

The album of the currently matched song

artiststring | undefined | null

The artist of the currently matched song

artworkmap | undefined

The artwork for the currently matched song. This may be undefined.

playoutStartUnixTimestampnumber (unix timestamp)

The unix timestamp of when the currently matched song started playing

playoutStartIsoTimestampstring (ISO timestamp)

The ISO timestamp of when the currently matched song started playing

scorenumber | undefined

The score (70-100) of the currently matched song indicating the confidence the system has that the matched track is the actual track being broadcasted.

spotifyTrackIdstring | null

The Spotify track ID for the currently matched song

spotifyAlbumIdstring | null

The Spotify album ID for the currently matched song

spotifyArtistIdsstring[] | null

The Spotify artist ID(s) for the currently matched song

youtubeVideoIdstring | null

The YouTube video ID for the currently matched song

Metadata
type LiveMusicRecognition = {
  status: 'match';
  metadata: {
    title: string;
    duration: Seconds | 'unknown';
    album: string | undefined | null;
    artist: string | undefined | null;
    artwork?: {
      original?: string;
      default?: string;
      '32x32'?: string;
      '64x64'?: string;
      '128x128'?: string;
      '256x256'?: string;
      '512x512'?: string;
    } | null;
    playoutStartUnixTimestamp: number;
    playoutStartIsoTimestamp: string;
    score: number | undefined;
    spotifyTrackId: string | null;
    spotifyAlbumId: string | null;
    spotifyArtistIds: string[] | null;
    youtubeVideoId: string | null;
  }
} | 
{
  status: 'noMatch';
  metadata: undefined;
}

Retrieve events in date range

Call the get events in range endpoint to return all events between specified start and end dates. The events will be returned sorted by start time.

startDate and endDate are required query params. They must be present for the endpoint to return successfully.

You may optionally pass an expand query param to expand the response. Multiple values can be passed as a comma-separated string (i.e. expand=artist,tags). Use expand=artist to hydrate the artistIds field with the full artist object for each event. Use expand=tags to hydrate the tagIds field with the full tag object for each event.

Endpoint
GET /api/station/:stationId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>
Query params (* required)
startDate*: ISO_Timestamp (indicating the beginning of the range you want events for)
endDate*: ISO_Timestamp (indicating the end of the range you want events for)
expand?: 'artist' | 'tags' | 'artist,tags' (optional)
Response
{
  schedules: Array<Event>,
  success: true,
}

Artists

The Artist object represents an instance of an artist (or presenter, or host, or whatever language you choose) in Radio Cult. An Artist is someone who presents shows on your station.

An Artist encapsulates the common information for a host or presenter - such as name, description, social media links and more.

As Artists can be assigned to shows, you can fetch all shows an Artist is on via their ID. Additionally, Events will have the ID for any Artist on that show.

Endpoints
GET    /api/station/:stationId/artists
GET    /api/station/:stationId/artists/:artistId
GET    /api/station/:stationId/artists/:slug
POST   /api/station/:stationId/artists
PUT    /api/station/:stationId/artists/:artistId
DELETE /api/station/:stationId/artists/:artistId
GET    /api/station/:stationId/artists/:artistId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>

The Artist object

Attributes

idstring

The unique ID of the artist

namestring

The name of the artist. As you can create an artist with only an email, it is possible for this value to not be set

stationIdstring

The unique ID of the station that the artist belongs to

slugstring

An alternative and human-readable ID of the artist

socialsmap

Map containing socials related to the artist - e.g. twitter handle, website. This can be undefined, as can the properties within

shareableLinkIdstring

The shareable Link that gives 3rd parties editable access to the artist. This may be useful if you are building an internal tool for your station. You most likely will not want to render this on any public facing site.

descriptionJSONContent | undefined

The artists description represented in TipTap JSON format

logomap

The artwork for the artist. If no artwork has been uploaded then this may be undefined. Once artwork has been uploaded it is automatically resized. The resizing happens asynchronously. As such, there is a possibility that any of the resize values may be undefined for a few seconds after the image has been uploaded. The time window is so small that you will be very unlikely to ever run into this.

tagsArray<string>

A string array containing the tags assigned to the artist

genresArray<string>

A string array containing the genres of the artist

countrystring

The country of the artist (this could be their country of residence or their country of origin)

modifiedstring [UTC timestamp]

A UTC timestamp of when the artist was last modified/updated

createdstring [UTC timestamp]

A UTC timestamp of when the artist was created

The artist object
{
    id: string;
    name?: string;
    stationId: string; 
    slug?: string;
    socials?: {
      twitterHandle?: string;
      instagramHandle?: string;
      facebook?: string;
      mixcloud?: string;
      soundcloud?: string;
      site?: string;
    };
    shareableLinkId: string;
    description?: JSONContent | undefined;
    logo?:  {
        default: string;
        '1024x1024': string;
        '32x32'?: string;
        '64x64'?: string;
        '128x128'?: string;
        '256x256'?: string;
        '512x512'?: string;
    };
    tags: Array<string>;
    genres: Array<string>;
    country?: string;
    modified: string;
    created: string;
}

Retrieve all artists

Call the get all artists endpoint to return all of your artists.

Endpoint
GET /api/station/:stationId/artists
Response
{
  success: true,
  artists: Array<Artist>
} 

Retrieve an artist by ID

Use an artist's ID to fetch their details.

Use your station ID and the ID of the artist you are interested in to build the URL.

Endpoint
GET /api/station/:stationId/artists/:artistId
Response
{
  success: true,
  artist: Artist
} 

Retrieve an artist by slug

Use an artist's slug to fetch their details.

Use your station ID and the slug of the artist you are interested in to build the URL.

Endpoint
GET /api/station/:stationId/artists/:slug
Response
{
  success: true,
  artist: Artist
} 

Retrieve an artist's schedules

Use an Artist's ID to fetch all events between the specified start and end dates the artist has been assigned to. The events will be returned sorted by start time.

startDate and endDate are required query params. They must be present for the endpoint to return successfully.

Endpoint
GET /api/station/:stationId/artists/:artistId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>
Query params (* required)
startDate*: ISO_Timestamp (the beginning of the range you want events within)
endDate*: ISO_Timestamp (the end of the range you want eventswithin)
Response
{
  schedules: Array<Event>,
  success: true,
}

Create an artist Automation

Create a new artist.

Use your station's ID to build the URL.

You must provide either email or name in the request body to create an artist. If an email is provided, then it must be a valid email address.

If provided, site must be a valid URL.

Lastly, if provided, description must either be a string or TipTap JSON format

Endpoint
POST /api/station/:stationId/artists
Body (JSON)
{
    name?: string,
    email: string,
    slug?: string,
    site?: string,
    twitterHandle?: string,
    instagramHandle?: string,
    facebook?: string,
    mixcloud?: string,
    soundcloud?: string,
    description?: string | JSONContent,
    tags?: string[],
    genres?: string[],
} |
{
    name: string,
    email?: string,
    slug?: string,
    site?: string,
    twitterHandle?: string,
    instagramHandle?: string,
    facebook?: string,
    mixcloud?: string,
    soundcloud?: string,
    description?: string | JSONContent,
    tags?: string[],
    genres?: string[],
}
Response
{
  success: true,
  artist: Artist
} 

Update an artist Automation

Call this endpoint to update an existing artist. Use the artist's ID to form the URL.

All fields are optional. Only the fields you provide are updated; omitted fields are left unchanged. socials is merged onto the artist's existing handles, so you only need to send the ones you want to change. To clear a value, send tags: [] or genres: [], or a social handle as an empty string.

If provided, email must be a valid email address, site must be a valid URL, and description must be TipTap JSON format.

Endpoint
PUT /api/station/:stationId/artists/:artistId
Body (JSON)
{
  shareableLinkId?: string,
  socials?: {
    site?: string,
    twitterHandle?: string,
    instagramHandle?: string,
    facebook?: string,
    mixcloud?: string,
    soundcloud?: string,
    youtube?: string,
  },
  email?: string,
  slug?: string,
  name?: string,
  description?: JSONContent,
  tags?: string[] | null,
  genres?: string[] | null,
  phoneNumber?: string,
  phoneAreaCode?: string,
  country?: string,
}
Response
{
  success: true,
  artist: Artist
} 

Delete an artist Automation

Call this endpoint to delete an artist. Use the artist's ID to form the URL.

If the artist is linked to a user, that user account is not deleted. Only the link between them is removed.

Endpoint
DELETE /api/station/:stationId/artists/:artistId
Response
{
  success: true,
} 

Last played

The last played endpoint can be used to retrieve the latest played tracks for your station.

Endpoint
GET    /api/station/:stationId/streaming/history/latest-results?limit=<number>

The Last played object

Attributes

playoutStartstring [UTC timestamp]

The start date of the last played track formatted as a ISO timestamp

titlestring

The title of the last played track

artiststring | null

The artist of the last played track

albumstring | null

The album of the last played track

artworkmap | null

The artwork of the last played track

The last played object
{
    playoutStart: string;
    title: string;
    artist: string | null;
    album: string | null;
    artwork: {
        default: string;
        '1024x1024': string;
        '32x32'?: string;
        '64x64'?: string;
        '128x128'?: string;
        '256x256'?: string;
        '512x512'?: string;
    } | null;
}

Get last played tracks

Call this endpoint to retrieve the latest played tracks for your station. The returned array will be sorted by playoutStart in descending order.

You may optionally pass a limit query param (expressed as an integer) to specify the number of latest played tracks to return. The minimum value is 1 and the maximum value is 100.

If not provided, the 5 last played tracks will be returned.

Endpoint
GET /api/station/:stationId/streaming/history/latest-results?limit=<number>
Query params
limit?: number (optional)
Response
{
    success: true,
    data: LastPlayed[]
} 

Tracks

Note: Track endpoints are disabled by default and are enabled on a case-by-case basis. Please reach out if you wish for the track endpoints to be enabled for your account.

The track endpoints can be used to interact with your track library.

You can upload files, tag them, add them to playlists, and more.

These endpoints need to be authenticated using your Secret Key.

Endpoints
GET    /api/station/:stationId/media/track
GET    /api/station/:stationId/media/track/:trackId/download-url
POST   /api/station/:stationId/media/track
PUT    /api/station/:stationId/media/track/:trackId
DELETE /api/station/:stationId/media/track/:trackId
POST   /api/station/:stationId/media/track/:trackId/upload/soundcloud
POST   /api/station/:stationId/media/track/:trackId/upload/mixcloud
PUT    /api/station/:stationId/media/track/:trackId/tag/:tagId
POST   /api/station/:stationId/media/playlist/:playlistId/entry  

The Track object

Attributes

idstring

The unique ID of the track

stationIdstring

The unique ID of the station that the track belongs to

mimeTypestring

The MIME type of the track

durationSeconds [number]

The duration of the track in seconds

titlestring

The title of the track

filenamestring

The file name of the track

artiststring

The artist of the track

albumstring

The album of the track

artworkmap | null

The artwork of the track

isrcstring

The ISRC of the track

fileSizeBytes [number]

The file size of the track in bytes

lastPlayedIsostring [UTC timestamp]

The last played date of the track formatted as a ISO timestamp

tagIdsArray<string> | undefined

An optional array of the IDs of tags assigned to the track

labelstring

The (music) label of the track

notesstring

The notes of the track

mixcloudUrlstring

The Mixcloud URL of the track (if successfully uploaded to Mixcloud)

soundcloudUrlstring

The Soundcloud URL of the track (if successfully uploaded to Soundcloud)

The track object
{
    id: string;
    stationId: string;
    mimeType: string;
    duration: Seconds;
    title: string;
    filename?: string;
    artist?: string;
    album?: string;
    artwork?: Artwork | null;
    isrc?: string;
    fileSize?: Bytes;
    lastPlayedIso?: string;
    tagIds?: string[];
    label?: string;
    notes?: string;
    mixcloudUrl?: string;
    soundcloudUrl?: string;
}

Retrieve all tracks Automation

Call the get all tracks endpoint to return all of your tracks.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/track
Response
{
    success: true,
    tracks: Array<Track>
} 

Retrieve a track's download URL Automation

Call the get track download URL endpoint to retrieve a signed URL that can be used to download the track.

The signed URL will expire after 30 minutes.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/track/:trackId/download-url
Response
{
    success: true,
    url: string
} 

Update a track Automation

Call this endpoint to update the metadata of an existing track. Use the track's ID to form the URL.

All body fields are optional - only the fields you provide will be updated.

If both cueIn and cueOut are provided, cueIn must be less than cueOut. If all of cueIn, cueOut, fadeIn and fadeOut are provided, then fadeIn + fadeOut must not exceed the playable duration (cueOut - cueIn).

Use your Secret Key when accessing this endpoint.

Endpoint
PUT /api/station/:stationId/media/track/:trackId
Body (JSON)
{
  title?: string,
  album?: string | null,
  artist?: string | null,
  isrc?: string | null,
  label?: string | null,
  isVisibleToDjs?: boolean,
  notes?: string (max 4000 characters),
  year?: number | null,
  genre?: string[] (1-10 items),
  bpm?: number | null,
  cueIn?: number,
  cueOut?: number,
  fadeIn?: number,
  fadeOut?: number,
}
Response
{
  success: true,
}

Delete a track Automation

Call this endpoint to delete a track from your track library. Use the track's ID to form the URL.

By default, if the track is still used by at least one playlist the request returns a 409 and the track is not deleted. Pass the optional force query param set to true to delete the track regardless of any playlist references.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/track/:trackId
Query params
force?: 'true' | 'false' (optional)
Response
{
  success: true,
}

Upload a track Automation

Note: This endpoint is disabled by default and is enabled on a case-by-case basis. Please reach out if you wish for this endpoint to be enabled for your account.

Call the upload endpoint to upload a file to your track library.

This endpoint is useful for building workflows and automating uploads when you have many Artists and shows.

The request takes a form data body, where stationMedia is the file you wish to upload.

The file must be mp3 or m4a. The file must be less than 750MB. The file must have a valid duration.

We use the metadata (or file name if metadata is not set) to set the track information.

OPTIONALLY: you can provide metadata overrides in the form data. This will override the metadata we extract from the file.

The notes field allows you to add custom notes, descriptions or comments to your tracks (max 4000 characters). These notes can be used for internal organization and will automatically populate as the default description when uploading to platforms like Mixcloud or Soundcloud from within Radio Cult.

NOTE: To ensure we can properly validate the metadata overrides, you must attach it to your form data as valid JSON. You need to JSON.stringify the metadata overrides before adding them to the form data.

OPTIONALLY: you can provide playlistIds and/or tagIds in the form data. This will assign the uploaded track to the provided playlist(s) and/or tag(s).

NOTE: If the provided playlist(s) and/or tag(s) cannot be found, the track will still be uploaded without the intended assignment.


Example code
import { createReadStream } from 'node:fs';
import FormData from 'form-data';
import { request } from 'undici';

const audioFile = createReadStream(filePath, {
  autoClose: true,
});

const formData = new FormData();
formData.append('stationMedia', audioFile);
formData.append(
  'metadata',
  JSON.stringify({
    title: 'Title',
    album: 'Album',
    notes: 'Notes about this track',
  })
);

playlistIds.forEach((playlistId) => formData.append('playlistIds', playlistId));
tagIds.forEach((tagId) => formData.append('tagIds', tagId));

await request(
  `https://api.radiocult.fm/api/station/${stationId}/media/track`,
  {
    method: 'POST',
    body: formData,
    headers: {
      ...formData.getHeaders(),
      'x-api-key': secretKey,
    },
  }
);
Endpoint
POST /api/station/:stationId/media/track
Body (form data)
stationMedia: mp3 or m4a file (max 750MB),

// Optional metadata overrides
metadata?: Stringified JSON<{
  title?: string,
  filename?: string,
  album?: string,
  artist?: string,
  isrc?: string,
  notes?: string (max 4000 characters),
}>

// Optional assignment IDs
playlistIds: string[] (max 5);
tagIds: string[] (max 5);
Response
{
  success: true,
  track: {
    id: string
  }
  // Only returned if request contained playlistIds and/or tagIds
  assignments: {
    playlists: {
      succeeded: string[];
      failed: string[];
    }
    tags: {
      succeeded: string[];
      failed: string[];
    }
  }
}

Upload to Soundcloud Automation

Note: This endpoint is disabled by default and is enabled on a case-by-case basis. Please reach out if you wish for this endpoint to be enabled for your account.

Call this endpoint to upload an existing file from your Radio Cult track library to your connected Soundcloud account.

This endpoint is useful for building workflows and automating uploads.

The request takes a form data body. Use the returned id from uploading a track to form the URL.

NOTE: To ensure we can properly validate the input, you must send valid JSON for all fields except artworkData. This means you must JSON.stringify the fields before sending them in the form data.


Example code
  const formData = new FormData();
  formData.append('tags', JSON.stringify(['rock', 'pop']));
  formData.append('title', JSON.stringify('Autumn Mix'));
  formData.append('embeddableBy', JSON.stringify('all'));
  formData.append('sharing', JSON.stringify('public'));
  formData.append('downloadable', String(true));
  formData.append('commentable', String(false));
Endpoint
POST /api/station/:stationId/media/track/:trackId/upload/soundcloud
Body (form data)
title: string,
tags: Array<string>,
embeddableBy: 'all' | 'me' | 'none',
sharing: 'public' | 'private',
downloadable: boolean,
commentable: boolean,
description?: string,
artworkData?: artwork file (max 2MB), 
Response
{
  success: true,
}

Upload to Mixcloud Automation

Note: This endpoint is disabled by default and is enabled on a case-by-case basis. Please reach out if you wish for this endpoint to be enabled for your account.

Call this endpoint to upload an existing file from your Radio Cult track library to your connected Mixcloud account.

This endpoint is useful for building workflows and automating uploads.

The request takes a form data body. Use the returned id from uploading a track to form the URL.

Some fields (disableComments, hideStats and hosts) require a Mixcloud Pro account.

NOTE: To ensure we can properly validate the input, you must send valid JSON for all fields except the artwork file. This means you must JSON.stringify the fields before sending them in the form data.

Endpoint
POST /api/station/:stationId/media/track/:trackId/upload/mixcloud
Body (form data)
name: string,
tags: Array<string>,
unlisted: boolean,
description?: string,
storedArtworkUrl?: string,
artwork?: artwork file,

// Mixcloud Pro account only
disableComments?: boolean,
hideStats?: boolean,
hosts?: Array<string> (max 2),
Response
{
  success: true,
}

Tag a track Automation

Call this endpoint to add a tag to an uploaded track.

Use the returned track ID from uploading a file to form the URL.

You can get the ID of a tag from the URL displayed in the tag view. For example, when viewing a tag your browser will display a URL like: https://app.radiocult.fm/tags?tag=2sZyt9DQDz8cLOUvFiZ2xS5MTIi. The tag ID in this case would be 2sZyt9DQDz8cLOUvFiZ2xS5MTIi.

This endpoint is useful for building workflows and automating uploads.

Endpoint
PUT /api/station/:stationId/media/track/:trackId/tag/:tagId
Response
{
  success: true,
}

Add a track to a playlist Automation

Call this endpoint to add an uploaded track to a playlist.

Use the returned track ID from uploading a file to form the URL.

You can get the ID of a playlist from the URL displayed in the playlist view. For example, when viewing a playlist your browser will display a URL like: https://app.radiocult.fm/playlists?playlist=2sZyt9DQDz8cLOUvFiZ2xS5MTIi. The playlist ID in this case would be 2sZyt9DQDz8cLOUvFiZ2xS5MTIi.

This endpoint is useful for building workflows and automating uploads.

Endpoint
POST /api/station/:stationId/media/playlist/:playlistId/entry
Body (JSON)
trackId: string
Response
{
  success: true,
}

Tags

The tag endpoints can be used to manage your tags. These endpoints are helpful when building automations and CLI workflows.

Due to the sensitive nature use your Secret Key when calling these endpoints.

Endpoints
GET    /api/station/:stationId/media/tag
POST   /api/station/:stationId/media/tag
PUT    /api/station/:stationId/media/tag/:tagId
DELETE /api/station/:stationId/media/tag/:tagId

The Tag object

Attributes

idstring

The unique ID of the tag

stationIdstring

The unique ID of the station that the tag belongs to

namestring

The name of the tag

colorstring [hex code]

The hex color of the tag

The tag object
{
    id: string;
    stationId: string;
    name: string;
    color: string;
}

Retrieve all tags Automation

Call the get all tags endpoint to return all of your tags.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/tag
Response
{
    success: true,
    tags: Array<Tag>
} 

Create a tag Automation

Call this endpoint to create a new tag. Use your station's ID to build the URL.

Use your Secret Key when accessing this endpoint.

Endpoint
POST /api/station/:stationId/media/tag
Body (JSON)
name: string (max 250 characters),
Response
{
    success: true,
    tag: Tag
} 

Update a tag Automation

Call this endpoint to update an existing tag. Use the tag's ID to form the URL.

Use your Secret Key when accessing this endpoint.

Endpoint
PUT /api/station/:stationId/media/tag/:tagId
Body (JSON)
name: string (max 250 characters),
Response
{
  success: true,
}

Delete a tag Automation

Call this endpoint to delete a tag. Use the tag's ID to form the URL.

Deleting a tag also removes it from any tracks and playlists it was assigned to.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/tag/:tagId
Response
{
  success: true,
}

Playlists

The playlist endpoints can be used to manage your playlists. These endpoints are helpful when building automations and CLI workflows.

Due to the sensitive nature use your Secret Key when calling these endpoints.

Endpoints
GET    /api/station/:stationId/media/playlist
POST   /api/station/:stationId/media/playlist
DELETE /api/station/:stationId/media/playlist/:playlistId
DELETE /api/station/:stationId/media/playlist/:playlistId/entry
DELETE /api/station/:stationId/media/playlist/:playlistId/entries

The Playlist object

Attributes

idstring

The unique ID of the playlist

stationIdstring

The unique ID of the station that the playlist belongs to

namestring

The name of the playlist

durationSeconds [number]

The duration of the playlist in seconds

playOrderstring

The order in which the playlist entries will play out. Either in order (in_order) or shuffled (shuffle)

numberOfSongsnumber

The total number of entries in the playlist (songs and tags)

numberOfTagsnumber

The total number of tags in the playlist

The playlist object
{
    id: string;
    stationId: string;
    name: string;
    duration: Seconds;
    playOrder: 'in_order' | 'shuffle'
    numberOfSongs: number;
    numberOfTags: number;
}

Retrieve all playlists Automation

Call the get all playlists endpoint to retrieve a list of all of your playlists.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/playlist
Response
{
    success: true,
    playlists: Array<Playlist>
} 

Create a playlist Automation

Call this endpoint to create a new, empty playlist. Use your station's ID to build the URL.

Use your Secret Key when accessing this endpoint.

Endpoint
POST /api/station/:stationId/media/playlist
Body (JSON)
name: string
Response
{
    success: true,
    playlist: Playlist
} 

Delete a playlist Automation

Call this endpoint to delete a playlist. Use the playlist's ID to form the URL.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/playlist/:playlistId
Response
{
    success: true,
} 

Delete a playlist entry Automation

Call this endpoint to remove a single entry (a song or a tag) from a playlist. Use the playlist's ID to form the URL.

The sortRanking in the body identifies the specific entry to remove within the playlist.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/playlist/:playlistId/entry
Body (JSON)
sortRanking: string
Response
{
    success: true,
} 

Clear a playlist's entries Automation

Call this endpoint to remove all entries (e.g. songs and tags) from a playlist. This will result in an empty playlist.

This endpoint is useful when automating content for repeating shows.

For example, you can create an event, attach a playlist to the event and make note of the playlist ID. You can then build a workflow where you clear the playlist, upload any new tracks and add to the playlist. You have effectively removed the audio for the previous show and prepared the playlist for the next occurrence of the show. All via the API.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/playlist/:playlistId/entries
Response
{
    success: true,
    playlist: Playlist
} 

Recordings

The recordings endpoints can be used to manage your recordings. These endpoints are helpful when building automations and CLI workflows.

Due to the sensitive nature use your Secret Key when calling these endpoints.

Endpoints
GET    /api/station/:stationId/media/recording
GET    /api/station/:stationId/media/recording/:recordingId/download-url
PUT    /api/station/:stationId/media/recording/:recordingId
DELETE /api/station/:stationId/media/recording/:recordingId
POST   /api/station/:stationId/media/recording/:recordingId/copy

The Recording object

Attributes

idstring

The unique ID of the recording

stationIdstring

The unique ID of the station that the recording belongs to

scheduleIdstring

The unique ID of the schedule event that was recorded to generate the recording

mimeTypestring

The mime type of the recording

durationSeconds [number]

The duration of the recording in seconds

titlestring

The title of the recording

artiststring

The artist (name) of the recording

fileSizeBytes [number]

The file size of the recording in bytes

notesstring

The notes of the recording

mixcloudUrlstring

The Mixcloud URL of the recording (if successfully uploaded to Mixcloud)

soundcloudUrlstring

The Soundcloud URL of the recording (if successfully uploaded to Soundcloud)

The recording object
{
    id: string;
    stationId: string;
    scheduleId: string;
    mimeType: string;
    duration: Seconds;
    title: string;
    artist?: string;
    fileSize?: Bytes;
    notes?: string;
    mixcloudUrl?: string;
    soundcloudUrl?: string;
}

Retrieve all recordings Automation

Call the get all recordings endpoint to retrieve a list of all of your recordings.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/recording
Response
{
    success: true,
    recordings: Array<Recording>
} 

Retrieve a recording's download URL Automation

Call the get recording download URL endpoint to retrieve a signed URL that can be used to download the recording.

The signed URL will expire after 30 minutes.

Use your Secret Key when accessing this endpoint.

Endpoint
GET /api/station/:stationId/media/recording/:recordingId/download-url
Response
{
    success: true,
    url: string
} 

Update a recording Automation

Call this endpoint to update the metadata of an existing recording. Use the recording's ID to form the URL.

All body fields are optional - only the fields you provide will be updated.

Use your Secret Key when accessing this endpoint.

Endpoint
PUT /api/station/:stationId/media/recording/:recordingId
Body (JSON)
title?: string,
artist?: string,
notes?: string (max 4000 characters),
Response
{
  success: true,
}

Delete a recording Automation

Call this endpoint to delete a recording. Use the recording's ID to form the URL.

Use your Secret Key when accessing this endpoint.

Endpoint
DELETE /api/station/:stationId/media/recording/:recordingId
Response
{
  success: true,
}

Copy a recording to your track library Automation

Call this endpoint to copy a recording into your track library as a track. Use the recording's ID to form the URL.

This is useful for turning a recorded show into a reusable track that you can add to playlists, tag, or upload to Mixcloud and Soundcloud.

Use your Secret Key when accessing this endpoint.

Endpoint
POST /api/station/:stationId/media/recording/:recordingId/copy
Response
{
  success: true,
}

Have any questions?

Feel free to reach out if you need a hand! We're more than happy to help explain the API, best practices or even spar a new concept.

Build your station website & automate your station

The Radio Cult API gives you programmatic access to your schedule, shows, and live now-playing data.

  • Real-time now-playing metadata
  • Full schedule and show data
  • Power custom websites and mobile apps
  • Automate file uploads and station management

Prefer to look first? Compare our plans.

Radio broadcaster on air
Hey AI, learn about us