Skip to Content

API Documentation

Programmatic access to your podcast data. List your podcasts and episodes, pull download metrics, create and publish episodes with their audio, and integrate with your own tools.

Authentication

All API requests require a Bearer token in the Authorization header. Create API keys from your account settings.

Authorization: Bearer fire_your_token_here

Tokens use the fire_ prefix followed by 64 hex characters. The raw token is shown once at creation — store it securely. If a token is lost, revoke it and create a new one.

Each key is either Read Only (the default) or Read/Write, chosen when you create it and changeable later under Account > API Keys, without replacing the key. Read Only keys can use every endpoint on this page. Endpoints that make changes need a Read/Write key, and are still limited to what your role on the podcast allows. Current User reports a key’s access as read_only or read_and_write.

Invalid or missing tokens return 401 Unauthorized:

{
  "error": {
    "message": "Invalid or missing API token",
    "code": "unauthorized"
  }
}

Base URL

All endpoints are under the /api/v1/ namespace:

https://fireside.fm/api/v1/

All responses are JSON. Endpoints return appropriate HTTP status codes:

  • 200 — Success
  • 201 — Created
  • 400 — A parameter or field is missing, unknown, or the wrong type
  • 401 — Invalid or missing token
  • 403 — Your role or plan doesn’t allow this (same rules as the Fireside dashboard), or a Read Only key tried to make a change
  • 404 — Resource not found (or not accessible to your account)
  • 422 — The change didn’t pass validation; nothing was saved
  • 429 — Rate limit exceeded

Rate Limiting

API requests are limited to 120 requests per minute per API token, or per IP address for unauthenticated requests. Every response includes rate limit headers:

Header Description
X-RateLimit-Limit Maximum requests per minute
X-RateLimit-Remaining Requests remaining in the current window
Retry-After Seconds to wait before retrying (only on 429 responses)

When the limit is exceeded, the API returns 429 Too Many Requests:

{
  "error": {
    "message": "Rate limit exceeded.",
    "code": "rate_limited"
  }
}

Current User

GET /api/v1/me

Returns the account the token belongs to. Useful for checking that a token works.

Response

{
  "data": {
    "name": "Jane Doe",
    "email": "[email protected]",
    "created_at": "2024-01-15T12:00:00Z",
    "api_token": {
      "name": "My CLI",
      "access": "read_only",
      "created_at": "2026-09-01T12:00:00Z"
    }
  }
}

List Podcasts

GET /api/v1/podcasts

Returns all podcasts you own or collaborate on. Only complete, active podcasts are included. Results are paginated (50 per page).

Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 50 Results per page, from 1 to 50. Ask for fewer to keep responses small.

Response

{
  "data": [
    {
      "token": "550e8400-e29b-41d4-a716-446655440000",
      "title": "My Podcast",
      "slug": "my-podcast",
      "description": "A podcast about things.",
      "subtitle": "Things and stuff",
      "author_name": "Jane Doe",
      "language": "en-us",
      "explicit": false,
      "artwork_url": "https://media24.fireside.fm/file/fireside-images-2024/podcasts/images/5/550e8400-e29b-41d4-a716-446655440000/cover.jpg?v=3",
      "created_at": "2024-01-15T12:00:00Z",
      "url": "https://my-podcast.fireside.fm",
      "feed_url": "https://feeds.fireside.fm/my-podcast/rss",
      "type": "episodic",
      "categories": [{ "name": "Tech News", "parent": "Technology" }],
      "copyright": "© 2026 My Podcast",
      "donation_url": null,
      "owner": { "name": "Jane Doe", "email": "[email protected]" }
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "max_per_page": 50,
    "previous": null,
    "next": 2
  }
}

The podcast fields are the same as the Get Podcast endpoint, except total_downloads which is only available on the show endpoint.

Get Podcast

GET /api/v1/podcasts/:podcast_token

Returns details for a single podcast, including total_downloads.

Response

{
  "data": {
    "token": "550e8400-e29b-41d4-a716-446655440000",
    "title": "My Podcast",
    "slug": "my-podcast",
    "description": "A podcast about things.",
    "subtitle": "Things and stuff",
    "author_name": "Jane Doe",
    "language": "en-us",
    "explicit": false,
    "artwork_url": "https://media24.fireside.fm/file/fireside-images-2024/podcasts/images/5/550e8400-e29b-41d4-a716-446655440000/cover.jpg?v=3",
    "total_downloads": 50000,
    "created_at": "2024-01-15T12:00:00Z",
    "url": "https://my-podcast.fireside.fm",
    "feed_url": "https://feeds.fireside.fm/my-podcast/rss",
    "type": "episodic",
    "categories": [{ "name": "Tech News", "parent": "Technology" }],
    "copyright": "© 2026 My Podcast",
    "donation_url": null,
    "owner": { "name": "Jane Doe", "email": "[email protected]" }
  }
}
Field Type Description
token string Unique podcast identifier (UUID). Use this in other API calls.
title string Podcast title
slug string URL slug
description string Podcast description
subtitle string or null Podcast subtitle
author_name string Author name
language string Language code (e.g. "en-us")
explicit boolean Whether the podcast is marked explicit
artwork_url string or null The podcast’s cover artwork, the same URL as its RSS feed’s itunes:image
total_downloads integer All-time total downloads for the podcast (show endpoint only)
created_at string Creation timestamp (ISO 8601)
url string The podcast's website, as listed in its RSS feed (custom domain or external site when set)
feed_url string The podcast's public RSS feed
type string episodic or serial
categories array Apple Podcasts categories, each with its name and parent category (or null)
copyright string The copyright line from the RSS feed
donation_url string or null Donation link, when it's shown in the feed
owner object The feed's owner name and email

List Episodes

GET /api/v1/podcasts/:podcast_token/episodes

Returns every episode of a podcast, including drafts and scheduled episodes, ordered by publish date (newest first). Results are paginated (100 per page). Requires the owner, manager, or producer role, the same as the episode pages in the Fireside dashboard.

Parameters

Parameter Type Default Description
status string all One of published, scheduled, or draft
page integer 1 Page number
per_page integer 100 Results per page, from 1 to 100. Ask for fewer to keep responses small.

Response

{
  "data": [
    {
      "token": "6a20c700-51d3-4c0a-abe7-da88d972a27c",
      "title": "Alternating Currents",
      "subtitle": "Tesla vs. Edison",
      "slug": "42",
      "season": 2,
      "episode_type": "full",
      "status": "published",
      "visibility": "public",
      "members_only": false,
      "explicit": false,
      "duration": 3120,
      "published_at": "2026-09-10T23:14:54Z",
      "created_at": "2026-09-01T12:00:00Z",
      "updated_at": "2026-09-10T23:14:54Z",
      "url": "https://my-podcast.fireside.fm/42",
      "preview_url": "https://my-podcast.fireside.fm/preview/x7Kq2mPa",
      "audio_url": "https://aphid.fireside.fm/d/1437767933/550e8400-e29b-41d4-a716-446655440000/6a20c700-51d3-4c0a-abe7-da88d972a27c.mp3",
      "audio_size": 49920000,
      "audio_status": "ready",
      "audio_error": null,
      "guid": "6a20c700-51d3-4c0a-abe7-da88d972a27c",
      "artwork_url": "https://media24.fireside.fm/file/fireside-images-2024/podcasts/images/5/550e8400-e29b-41d4-a716-446655440000/cover.jpg?v=3",
      "transcript_url": "https://media24.fireside.fm/file/fireside-images-2024/podcasts/transcripts/5/550e8400-e29b-41d4-a716-446655440000/episodes/6/6a20c700-51d3-4c0a-abe7-da88d972a27c/transcript.txt",
      "chapters_url": "https://feeds.fireside.fm/my-podcast/json/episodes/6a20c700-51d3-4c0a-abe7-da88d972a27c/chapters",
      "player_url": "https://fireside.fm/player/v2/AbCd1234+EfGh5678",
      "player_embed_code": "<iframe src=\"https://fireside.fm/player/v2/AbCd1234+EfGh5678\" width=\"740\" height=\"200\" frameborder=\"0\" scrolling=\"no\"></iframe>",
      "soundbite": { "title": "The best bit", "start_time": 90, "duration": 30 },
      "hosts": [{ "name": "Jane Doe", "url": "https://janedoe.example.com" }],
      "guests": [{ "name": "Sam Lee", "url": null }]
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 100,
    "max_per_page": 100,
    "previous": null,
    "next": null
  }
}
Field Type Description
status string published, scheduled, or draft. An episode is a draft until it has audio, a publish date, and isn’t private.
visibility string public, unlisted, or private
slug string URL slug. For numbered episodes this is the episode number.
duration integer or null Length in seconds
published_at string or null Publish date (ISO 8601). In the future for scheduled episodes; null for drafts with no date.
url string or null Public episode page. Only set for published episodes.
preview_url string Private preview page, available in every state, including drafts. Anyone with this link can see and play the episode without logging in, so share it only with people you’d show an unreleased episode to. Use url for public links.
audio_url string or null The audio file URL used in your RSS feed. Only set once audio is uploaded.
audio_size integer or null Audio file size in bytes
audio_status string processing while uploaded audio transfers (any earlier audio keeps playing meanwhile), ready, failed (see audio_error), or none
audio_error string or null Why the last audio transfer failed
guid string The episode's RSS GUID, which podcast apps use to identify it (the original GUID for imported episodes)
artwork_url string The episode's artwork, or the podcast's when the episode has none, as in the feed
transcript_url string or null Plain-text transcript, when one is uploaded
chapters_url string or null Chapters JSON (Podcasting 2.0 format), when the episode has chapters
player_url string The embeddable web player for this episode
player_embed_code string HTML for embedding that player
soundbite object or null A highlight clip: title, start_time and duration in seconds
hosts, guests array The hosts and guests shown on the episode’s page, each with a name and url (or null). People hidden from your site are left out. Hosts are in the order you set; guests are alphabetical.

Get Episode

GET /api/v1/podcasts/:podcast_token/episodes/:episode_token

Returns a single episode with the same fields as List Episodes, plus description (the show notes).

Create Episode

POST /api/v1/podcasts/:podcast_token/episodes

Creates a draft episode, starting from the podcast’s episode defaults as a new episode in the dashboard does. It stays private until you publish it. Needs a Read/Write key and the producer role. Send a JSON body (Content-Type: application/json) with any of these fields:

Field Type Description
title string The episode title
subtitle string or null A one-line summary
slug string The path of the episode’s page: lower-case letters, numbers and dashes, unique within the podcast. Defaults to the next episode number.
description string or null Show notes, in Markdown
season integer or null Season number, from 0
episode_type string full, trailer, or bonus
explicit boolean Whether the episode has explicit content
audio_file_url string An MP3 from Upload a File. It transfers in the background; watch audio_status.
cover_file_url string Episode cover art from Upload a File
transcript_file_url string A plain-text transcript from Upload a File

Returns 201 Created with the episode, as in Get Episode. Unknown fields are refused with a 400 rather than ignored.

Cover art and transcripts transfer during the request. If one can’t be processed, the response is 422 with the code upload_failed, naming the file; the episode’s other changes are still saved, and the response’s data is the episode, so you can retry the file with an update. Resending an audio file_url after its transfer failed retries it.

Validation errors return 422, keyed by the field you sent:

{
  "error": {
    "message": "slug has already been taken",
    "code": "validation_failed",
    "fields": {
      "slug": ["has already been taken"]
    }
  }
}

A Read Only key gets 403 on every endpoint that makes changes:

{
  "error": {
    "message": "Token does not have write access. Change this key to Read/Write under Account > API Keys to make changes.",
    "code": "write_access_required"
  }
}

While a podcast is on hiatus, suspended, or taken down, its episodes can still be read but not changed, as in the dashboard. Writes then return 403 with the code podcast_inactive.

Update Episode

PATCH /api/v1/podcasts/:podcast_token/episodes/:episode_token

Changes the fields you send, from the same list as Create Episode, and leaves the rest alone. Changes to a published episode go live right away, and a new slug changes its URL. Release date and visibility change only through publish and unpublish. Returns the updated episode.

Publish Episode

POST /api/v1/podcasts/:podcast_token/episodes/:episode_token/publish

Releases an episode now, on a schedule, or backdated. The episode needs audio; one without returns 422 with the code audio_required. If the episode is set in the dashboard to be posted to the podcast’s connected social accounts, publishing posts it, as it does from the dashboard. Returns the episode.

Field Type Default Description
published_at string now ISO 8601 release time, like 2026-10-12T09:00:00-04:00. A future time schedules the episode. Without an offset it’s read in the podcast’s time zone. Omitted, an episode that’s already published keeps its date.
visibility string public for drafts public, or unlisted to reach it only by its link. Omitted, a public or unlisted episode keeps its visibility.

Unpublish Episode

POST /api/v1/podcasts/:podcast_token/episodes/:episode_token/unpublish

Makes the episode a private draft, taking it out of the feed and off the website. Its published_at is kept, so publishing again with that time puts it back in place. Returns the episode.

Upload a File

POST /api/v1/podcasts/:podcast_token/uploads

Episode audio, cover art and transcripts upload in two steps. First ask for a signed upload URL, describing the file; it’s checked against your plan’s limits before anything is sent. Then upload the file with an HTTP PUT to upload_url within the hour, sending the returned headers, and attach its file_url to an episode with Create Episode or Update Episode. Needs a Read/Write key and the producer role.

Field Type Description
kind string audio (MP3), cover (JPG, PNG, GIF or WebP), or transcript (plain text)
filename string The file’s name, with an extension that matches its kind
byte_size integer The file’s size in bytes, within your plan’s MP3 limit for audio, 1.91 MB for cover art, or 195 KB for transcripts
content_type string audio/mpeg, image/jpeg, image/png, image/gif, image/webp, or text/plain

Response

{
  "data": {
    "kind": "audio",
    "upload_url": "https://s3.amazonaws.com/...",
    "method": "PUT",
    "headers": { "Content-Type": "audio/mpeg" },
    "file_url": "https://s3.amazonaws.com/...",
    "expires_at": "2026-10-12T15:00:00Z"
  }
}

Upload, then attach:

curl -X PUT -T episode.mp3 -H "Content-Type: audio/mpeg" "$UPLOAD_URL"

curl -X PATCH https://fireside.fm/api/v1/podcasts/:podcast_token/episodes/:episode_token \
  -H "Authorization: Bearer fire_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"audio_file_url": "'"$FILE_URL"'"}'

Attaching checks the uploaded file is one granted for that podcast and still within the limit. A file that isn’t returns 422 and nothing on the episode changes.

Episode Metrics

GET /api/v1/podcasts/:podcast_token/metrics/episodes

Per-episode download statistics for all published episodes, ordered by publish date (newest first). Results are paginated (100 per page). Each episode has the same fields as List Episodes, plus downloads.

Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 100 Results per page, from 1 to 100. Ask for fewer to keep responses small.

Response

{
  "data": [
    {
      "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "title": "Episode Title",
      "subtitle": null,
      "slug": "episode-slug",
      "season": 2,
      "episode_type": "full",
      "status": "published",
      "visibility": "public",
      "members_only": false,
      "explicit": false,
      "duration": 1830,
      "published_at": "2026-03-01T05:00:00Z",
      "created_at": "2026-02-20T12:00:00Z",
      "updated_at": "2026-03-01T05:00:00Z",
      "url": "https://mypodcast.fireside.fm/episode-slug",
      "preview_url": "https://mypodcast.fireside.fm/preview/x7Kq2mPa",
      "audio_url": "https://aphid.fireside.fm/d/1437767933/550e8400-e29b-41d4-a716-446655440000/a1b2c3d4-e5f6-7890-abcd-ef1234567890.mp3",
      "audio_size": 29280000,
      "audio_status": "ready",
      "audio_error": null,
      "downloads": {
        "1_day": 500,
        "7_day": 1200,
        "14_day": 1800,
        "30_day": 2500,
        "90_day": 4000,
        "spotify": 300,
        "total": 5000
      }
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 100,
    "max_per_page": 100,
    "previous": null,
    "next": 2
  }
}
Field Type Description
Episode fields The same fields as List Episodes
downloads.1_day integer or null Downloads within 1 day of publish. null if not enough time has passed.
downloads.7_day integer or null Downloads within 7 days of publish
downloads.14_day integer or null Downloads within 14 days of publish
downloads.30_day integer or null Downloads within 30 days of publish
downloads.90_day integer or null Downloads within 90 days of publish
downloads.spotify integer Total Spotify streams, or 0 when the podcast has none. Already counted inside downloads.total.
downloads.total integer All-time total downloads for this episode, including any Spotify streams
pagination.page integer Current page number
pagination.per_page integer Results per page
pagination.max_per_page integer The most per_page can be for this endpoint
pagination.previous integer or null Previous page number, or null if on the first page
pagination.next integer or null Next page number, or null if on the last page

Downloads by Month

GET /api/v1/podcasts/:podcast_token/metrics/downloads

Monthly download totals for the podcast, in reverse chronological order. Results are paginated (36 per page).

Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 36 Results per page, from 1 to 36. Ask for fewer to keep responses small.

Response

{
  "data": [
    { "date": "2026-03-01", "value": 1500 },
    { "date": "2026-02-01", "value": 1200 }
  ],
  "meta": {
    "total_downloads": 50000
  },
  "pagination": {
    "page": 1,
    "per_page": 36,
    "max_per_page": 36,
    "previous": null,
    "next": 2
  }
}
Field Type Description
data[].date string First day of the period (YYYY-MM-DD)
data[].value integer Total downloads for that period
meta.total_downloads integer All-time total downloads for the podcast
pagination.page integer Current page number
pagination.per_page integer Results per page
pagination.max_per_page integer The most per_page can be for this endpoint
pagination.previous integer or null Previous page number, or null if on the first page
pagination.next integer or null Next page number, or null if on the last page

Downloads by Day

GET /api/v1/podcasts/:podcast_token/metrics/daily
GET /api/v1/podcasts/:podcast_token/episodes/:episode_token/metrics/daily

Downloads per day for the whole podcast, or for one episode, oldest first. Every day in the range is listed, including days with none. Days are the podcast’s local calendar days, as in the dashboard.

Parameters

Parameter Type Default Description
start_date date 29 days before end_date First day, like 2026-10-01
end_date date today Last day, in the podcast’s time zone

A range can cover at most 90 days; request longer periods in parts.

Response

{
  "data": [
    { "day": "2026-10-01", "downloads": 412, "spotify": 38, "total": 450 },
    { "day": "2026-10-02", "downloads": 297, "spotify": 21, "total": 318 }
  ],
  "meta": {
    "start_date": "2026-10-01",
    "end_date": "2026-10-02",
    "time_zone": "Eastern Time (US & Canada)",
    "downloads": 709,
    "spotify": 59,
    "total": 768
  }
}

downloads are counted by Fireside; spotify are Spotify’s own counts, reported separately; total adds the two.

Quick Start

1. Create an API key from your API Keys page.

2. List your podcasts:

curl -H "Authorization: Bearer fire_your_token" \
  https://fireside.fm/api/v1/podcasts

3. Get episode metrics using a podcast token from the response:

curl -H "Authorization: Bearer fire_your_token" \
  https://fireside.fm/api/v1/podcasts/PODCAST_TOKEN/metrics/episodes

4. Get monthly downloads:

curl -H "Authorization: Bearer fire_your_token" \
  https://fireside.fm/api/v1/podcasts/PODCAST_TOKEN/metrics/downloads