This document describes the REST API endpoints for podcast media processing.
https://api.studio.inlet.fmAll API endpoints require authentication using a Token in the Authorization header. The API key is associated with the user and grants access to all podcasts owned by that user.
Authorization: Token <API_KEY>POST https://api.studio.inlet.fm/api/v1/podcasts/:podcastId/media/process
Triggers a media processing flow for a given media URL. The system will process the media for ad break detection and insertion according to the podcast's configuration.
{
"url": "https://some.server.com/media.mp3",
"name": "Media title",
"description": "Media description. Links are supported: www.google.com", // (optional)
"publishedDate": "2025-10-01T14:30:00.000Z", // (optional)
"adOptions": {} // (optional) see below
}url (required): The media URL to processname (required): The title/name for the mediadescription (optional) Text blob describing the media episodeadOptions (optional): Object containing ad insertion/removal configurationpublishedDate(optional) Date object in ISO 8601 format (e.g., 2025-10-01T14:30:00.000Z)type MediaCreationParams = {
url: string;
name: string;
description?: string;
adOptions?: AdOptions;
publishedDate?: string;
}Ad Options
Ad Options allow you to customize the ad injection experience.
preRoll (optional): Pre-roll ad configuration with minDuration, maxDuration, and adCountpostRoll (optional): Post-roll ad configuration with minDuration, maxDuration, and adCountautomatedMidRolls (optional): Automated mid-roll configuration for AI-generated ad placementsmidRolls (optional): Array of specific mid-roll placements with time, minDuration, maxDuration, and adCountEach of the options above can be further customized as follows:
minDuration (optional) The minimum ad length in secondsmaxDuration (optional) The maximum ad length in secondsadCount (required) The number of ads to be played at the ad breakinsertionCount (optional) A manual override of the number of ad breaks to be insertedadsPerHour (optional) A manual override to define the number of ads per hour to be insertedtime For MidRollOption, the specific time in seconds of where an ad marker will be insertedtype AdConfiguration = {
minDuration?: number;
maxDuration?: number;
adCount: number;
}
type AutomatedMidRollOption = {
minDuration?: number;
maxDuration?: number;
adCount: number;
insertionCount?: number;
adsPerHour?: number;
}
type MidRollOption = {
minDuration?: number;
maxDuration?: number;
adCount: number;
time: number;
}
type AdOptions = {
preRoll?: AdConfiguration;
postRoll?: AdConfiguration;
automatedMidRolls?: AutomatedMidRollOption;
midRolls?: MidRollOption[];
}automatedMidRolls options of 3 ads to be played at a rate of 2 ad breaks per hour.curl -X POST https://api.studio.inlet.fm/api/v1/podcasts/507f1f77bcf86cd799439011/media/process \
-H "Authorization: Token your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/media/episode.mp3",
"name": "My Podcast Episode",
"adOptions": {
"preRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"postRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"automatedMidRolls": {
"adCount": 3,
"adsPerHour": 2
}
}
}'automatedMidRolls options of 4 ad breaks to be detected with 2 ads to be played at each ad break.curl -X POST https://api.studio.inlet.fm/api/v1/podcasts/507f1f77bcf86cd799439011/media/process \
-H "Authorization: Token your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/media/episode.mp3",
"name": "My Podcast Episode",
"adOptions": {
"preRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"postRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"automatedMidRolls": {
"adCount": 2,
"insertionCount": 4
}
}
}'midRolls - which allows for custom placement of midroll ads in the media file. Each midroll can be customized with the minimum duration: minDuration, maximumDuration :maxDuration, and the number of ads to be played: adCount. With this example, an ad break is inserted at the 5 second mark and 90 second mark.curl -X POST https://api.studio.inlet.fm/api/v1/podcasts/507f1f77bcf86cd799439011/media/process \
-H "Authorization: Token your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/media/episode.mp3",
"name": "My Podcast Episode",
"adOptions": {
"preRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"postRoll": {
"adCount": 1,
"minDuration": 15,
"maxDuration": 30
},
"midRolls": [
{
maxDuration?: 15;
adCount: 1;
time: 5;
},
{
maxDuration?: 15;
adCount: 1;
time: 90;
},
]
}
}'{
"success": true,
"message": "Media processing started successfully",
"data": {
"mediaId": "507f1f77bcf86cd799439012",
"status": "AD_BREAK_QUEUED",
"name": "My Podcast Episode",
"originUrl": "https://example.com/media/episode.mp3"
}
}GET https://api.studio.inlet.fm/api/v1/podcasts/:podcastId/media/:mediaId
Retrieves the current status and details of a media processing job.
curl -X GET https://api.studio.inlet.fm/api/v1/podcasts/507f1f77bcf86cd799439011/media/507f1f77bcf86cd799439012 \
-H "Authorization: Token your-api-key-here"{
"success": true,
"data": {
"mediaId": "507f1f77bcf86cd799439012",
"name": "My Podcast Episode",
"status": "READY",
"originUrl": "https://example.com/media/episode.mp3",
"url": "https://processed-media-url.com/episode.mp3",
"duration": 1800,
"publishedDate": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:25:00.000Z",
"failedAttempts": 0,
"adRemovalMarkers": []
}
}The status field in responses can have the following values:
IMPORTED: Media source has been createdUPLOAD_QUEUED: Media upload has been queuedUPLOADING: Currently uploading mediaFETCH_COMPLETE: Media fetch completed successfullyPROCESSING_QUEUED: Processing has been queuedAI_ERROR: Error occurred during AI processingAD_BREAK_QUEUED: Ad break detection queuedAD_BREAK_PROCESSING: Currently processing ad breaksAD_BREAK_ERROR: Error occurred during ad break processingAD_BREAK_READY: Ad break processing completedREMOVE_ADS_WAITING: Waiting for ad removal processingREMOVE_ADS_QUEUED: Ad removal queuedREMOVE_ADS_PROCESSING: Currently removing adsREMOVE_ADS_ERROR: Error occurred during ad removalREMOVE_ADS_READY: Ad removal completedPUBLISHING: Currently publishing to platformsPUBLISHING_ERROR: Error occurred during publishingERROR: General error occurredUNAVAILABLE: Reference Media URL is unavailableREADY: Media is fully processed and readyAll endpoints return consistent error responses:
{
"error": "Error Type",
"message": "Detailed error message"
}200: Success201: Created (for POST requests)400: Bad Request (missing or invalid parameters)401: Unauthorized (missing or invalid API key)403: Forbidden (API access not enabled or media doesn't belong to podcast)404: Not Found (podcast or media not found)500: Internal Server ErrorThe media processing follows this general flow:
The initial status after submitting media is AD_BREAK_QUEUED, which indicates the media has been queued for ad break analysis.
To monitor the progress of a media processing job, poll the status endpoint:
# Poll every 30 seconds
while true; do
curl -X GET https://api.studio.inlet.fm/api/v1/v1/podcasts/507f1f77bcf86cd799439011/media/507f1f77bcf86cd799439012 \
-H "Authorization: Token your-api-key-here"
sleep 30
doneTo enable API access, you need to generate an API key for your user account. This can be done through the GraphQL API:
mutation GenerateApiKey {
generateApiKey
}The API key is associated with the user and grants access to all podcasts owned by that user. You can also query your current API key:
query MyApiKey {
myApiKey
}Currently, there are no rate limits implemented, but it's recommended to: