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— Success201— Created400— A parameter or field is missing, unknown, or the wrong type401— Invalid or missing token403— Your role or plan doesn’t allow this (same rules as the Fireside dashboard), or a Read Only key tried to make a change404— Resource not found (or not accessible to your account)422— The change didn’t pass validation; nothing was saved429— 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