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.
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.
'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.
{
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.
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.
{
"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.
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.
{
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:
schedule- which means a scheduled event is playing,offAir- which means your stream is off air and nothing is playing, ordefaultPlaylist- 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
Metadataof the track details currently being played on the stream. See below for more details on the shape of theMetadataobject. - the
LiveMusicRecognitionof 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 theLiveMusicRecognitionobject.
GET /api/station/:stationId/schedule/live
{
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.
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
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
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.
GET /api/station/:stationId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>
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)
{
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.
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
{
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.
GET /api/station/:stationId/artists
{
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.
GET /api/station/:stationId/artists/:artistId
{
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.
GET /api/station/:stationId/artists/:slug
{
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.
GET /api/station/:stationId/artists/:artistId/schedule?startDate=<iso_timestamp>&endDate=<iso_timestamp>
startDate*: ISO_Timestamp (the beginning of the range you want events within)
endDate*: ISO_Timestamp (the end of the range you want eventswithin)
{
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
POST /api/station/:stationId/artists
{
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[],
}
{
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.
PUT /api/station/:stationId/artists/:artistId
{
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,
}
{
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.
DELETE /api/station/:stationId/artists/:artistId
{
success: true,
}
Last played
The last played endpoint can be used to retrieve the latest played tracks for your station.
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
{
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.
GET /api/station/:stationId/streaming/history/latest-results?limit=<number>
limit?: number (optional)
{
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.
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)
{
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.
GET /api/station/:stationId/media/track
{
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.
GET /api/station/:stationId/media/track/:trackId/download-url
{
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.
PUT /api/station/:stationId/media/track/:trackId
{
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,
}
{
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.
DELETE /api/station/:stationId/media/track/:trackId
force?: 'true' | 'false' (optional)
{
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.
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,
},
}
);
POST /api/station/:stationId/media/track
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);
{
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.
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));
POST /api/station/:stationId/media/track/:trackId/upload/soundcloud
title: string,
tags: Array<string>,
embeddableBy: 'all' | 'me' | 'none',
sharing: 'public' | 'private',
downloadable: boolean,
commentable: boolean,
description?: string,
artworkData?: artwork file (max 2MB),
{
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.
POST /api/station/:stationId/media/track/:trackId/upload/mixcloud
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),
{
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.
PUT /api/station/:stationId/media/track/:trackId/tag/:tagId
{
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.
POST /api/station/:stationId/media/playlist/:playlistId/entry
trackId: string
{
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.
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
{
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.
GET /api/station/:stationId/media/tag
{
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.
POST /api/station/:stationId/media/tag
name: string (max 250 characters),
{
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.
PUT /api/station/:stationId/media/tag/:tagId
name: string (max 250 characters),
{
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.
DELETE /api/station/:stationId/media/tag/:tagId
{
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.
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
{
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.
GET /api/station/:stationId/media/playlist
{
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.
POST /api/station/:stationId/media/playlist
name: string
{
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.
DELETE /api/station/:stationId/media/playlist/:playlistId
{
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.
DELETE /api/station/:stationId/media/playlist/:playlistId/entry
sortRanking: string
{
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.
DELETE /api/station/:stationId/media/playlist/:playlistId/entries
{
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.
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)
{
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.
GET /api/station/:stationId/media/recording
{
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.
GET /api/station/:stationId/media/recording/:recordingId/download-url
{
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.
PUT /api/station/:stationId/media/recording/:recordingId
title?: string,
artist?: string,
notes?: string (max 4000 characters),
{
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.
DELETE /api/station/:stationId/media/recording/:recordingId
{
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.
POST /api/station/:stationId/media/recording/:recordingId/copy
{
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.

