Media Management API

This document describes the REST API endpoints for podcast media processing.

Base URL

https://api.studio.inlet.fm

Authentication

All 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>

Endpoints

1. Process Media

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.

Request Body

{
  "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
}

Request Body Fields

  • url (required): The media URL to process
  • name (required): The title/name for the media
  • description (optional) Text blob describing the media episode
  • adOptions (optional): Object containing ad insertion/removal configuration
  • publishedDate(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 adCount
  • postRoll (optional): Post-roll ad configuration with minDuration, maxDuration, and adCount
  • automatedMidRolls (optional): Automated mid-roll configuration for AI-generated ad placements
  • midRolls (optional): Array of specific mid-roll placements with time, minDuration, maxDuration, and adCount
  • Each of the options above can be further customized as follows:

  • minDuration (optional) The minimum ad length in seconds
  • maxDuration (optional) The maximum ad length in seconds
  • adCount (required) The number of ads to be played at the ad break
  • insertionCount (optional) A manual override of the number of ad breaks to be inserted
  • adsPerHour (optional) A manual override to define the number of ads per hour to be inserted
  • time For MidRollOption, the specific time in seconds of where an ad marker will be inserted
  • type 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[];
    }

    Example Requests

    1. Uploading media with 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
          }
        }
      }'
    1. Uploading media with 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
          }
        }
      }'
    1. Uploading media with 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;
            },
          ]
        }
      }'

    Response

    {
      "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"
      }
    }

    2. Check Media Status

    GET https://api.studio.inlet.fm/api/v1/podcasts/:podcastId/media/:mediaId

    Retrieves the current status and details of a media processing job.

    Example Request

    curl -X GET https://api.studio.inlet.fm/api/v1/podcasts/507f1f77bcf86cd799439011/media/507f1f77bcf86cd799439012 \
      -H "Authorization: Token your-api-key-here"

    Response

    {
      "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": []
      }
    }

    Status Values

    The status field in responses can have the following values:

  • IMPORTED: Media source has been created
  • UPLOAD_QUEUED: Media upload has been queued
  • UPLOADING: Currently uploading media
  • FETCH_COMPLETE: Media fetch completed successfully
  • PROCESSING_QUEUED: Processing has been queued
  • AI_ERROR: Error occurred during AI processing
  • AD_BREAK_QUEUED: Ad break detection queued
  • AD_BREAK_PROCESSING: Currently processing ad breaks
  • AD_BREAK_ERROR: Error occurred during ad break processing
  • AD_BREAK_READY: Ad break processing completed
  • REMOVE_ADS_WAITING: Waiting for ad removal processing
  • REMOVE_ADS_QUEUED: Ad removal queued
  • REMOVE_ADS_PROCESSING: Currently removing ads
  • REMOVE_ADS_ERROR: Error occurred during ad removal
  • REMOVE_ADS_READY: Ad removal completed
  • PUBLISHING: Currently publishing to platforms
  • PUBLISHING_ERROR: Error occurred during publishing
  • ERROR: General error occurred
  • UNAVAILABLE: Reference Media URL is unavailable
  • READY: Media is fully processed and ready
  • Error Responses

    All endpoints return consistent error responses:

    {
      "error": "Error Type",
      "message": "Detailed error message"
    }

    Common HTTP Status Codes

  • 200: Success
  • 201: 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 Error
  • Processing Flow

    The media processing follows this general flow:

    1. Media Upload/Reference: Media is referenced by URL and a MediaSource record is created
    2. Ad Break Detection: The system analyzes the media for optimal ad break placement
    3. Ad Insertion: Ads are inserted at detected or specified break points
    4. Publishing: Processed media is published to configured platforms
    5. Ready: Media is available for distribution

    The initial status after submitting media is AD_BREAK_QUEUED, which indicates the media has been queued for ad break analysis.

    Polling for Status

    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
    done

    Setting Up API Keys

    To 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
    }

    Rate Limiting

    Currently, there are no rate limits implemented, but it's recommended to:

  • Poll status endpoints no more frequently than every 30 seconds
  • Limit concurrent media processing requests to avoid overwhelming the system
  • Implement exponential backoff for retries
  • Notes

  • The API is designed to work alongside the existing GraphQL API
  • All media processing follows the same pipeline as the existing system
  • API keys are associated with users and grant access to all podcasts owned by that user
  • The system supports general media URLs for processing (not limited to YouTube)
  • Ad options are configurable per request and support both automated and manual ad placement
  • Media processing begins with ad break detection and insertion, not media fetching