Episodes
Episodes per show, search, transcripts, tags, goals and Substack download figures.
List a show's episodes
/v1/shows/{show_id}/episodesA show's episodes as the Episodes page lists them: every episode the app knows (stored feed, Spotify chart, Apple and cluster-derived, newest first) with its cluster's reach by category and form, clips and posts, engagement, tags, brands, freshness and the cluster's public URL. meta.episode_count is the full count.
time_range (all, 30d, 90d, quarter, year; or start_date + end_date) filters on the publish date; undated episodes never fall inside an active window. series, guests and format match episode tags (any-of). has_cluster=true keeps episodes whose cluster exists or has reach. view=goals adds per-episode target deltas from the show's episode goals; view=benchmark adds deltas against same-format peer medians (minimum 3 peers) and the ≥ 3× breakout badge.
SDKlistener.shows.episodes.list()client.shows.episodes.list()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired
Query parameters
- 7d | 14d | 30d | 90d | 180d | 365d | all, or a quarter like 2026-Q2. Windows are UTC days anchored to today.
time_rangestringOne ofall30d90dquarteryearDefault
"all" - First day, YYYY-MM-DD (inclusive). With end_date, overrides time_range.
start_datestring - Last day, YYYY-MM-DD (inclusive). With start_date, overrides time_range.
end_datestring - Series tags. Repeat the parameter or comma-separate values.
seriesarray of strings - Guest tags. Repeat the parameter or comma-separate values.
guestsarray of strings - Format tags. Repeat the parameter or comma-separate values.
formatarray of strings - Brand name or slug filter.
brandstring - Case-insensitive text filter.
searchstring has_clusterboolean- Sort field.
sort_bystringOne ofdatetotal_reachyoutube_reachaudio_reachsocial_reachlong_form_reachshort_form_reachclipspoststitleDefault
"date" - asc or desc.
sort_orderstringOne ofascdescDefault
"desc" viewstringOne ofsimplegoalsbenchmarkDefault
"simple"- Page size, 1–100 (default 25).
limitintegerDefault
25 - Opaque cursor from the previous page's next_cursor.
cursorstring
Returns
200OK
objectstringrequiredurlstringrequireddataarray of objectsrequiredShow child attributesHide child attributes
has_morebooleanrequired- Pass as
next_cursorstringrequiredcursorto get the next page; null on the last page. - The result's non-list fields (window, coverage, freshness, totals, note …).
metaobjectrequiredShow child attributesHide child attributes
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found429rate_limited500internal_error
Retrieve an episode
/v1/shows/{show_id}/episodes/{episode_id}One episode: its episodes-table row (reach by category and form, clips and posts, engagement, tags, brands), stored Spotify / Apple / YouTube stats when present, a summary of its cluster (type, node counts, sponsor brands, linked campaigns, freshness), goal deltas and benchmark bucket. episode_id is any id GET /v1/shows/{show_id}/episodes or GET /v1/episodes/search returns (Spotify, manual-<ts>, Apple or synthetic ids).
SDKlistener.shows.episodes.retrieve()client.shows.episodes.retrieve()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired - Episode id (see GET /v1/shows/{show_id}/episodes).
episode_idstringrequired
Returns
200OK
- The minimal show reference embedded in cross-show results.
showobjectrequiredShow child attributesHide child attributes
- One episodes-table row: the episode plus its source cluster's reach.
episodeobjectrequiredShow child attributesHide child attributes
computed_atstringrequiredcache_age_secondsnumberrequiredobjectstringrequired- Index sources that produced the row (stored feed, chart, apple, cluster, provider).
sourcesarray of strings - Spotify chart / stored stats for the episode when present.
spotifyobject appleobjectyoutubeobjectclusterobjectShow child attributesHide child attributes
goalsobjectShow child attributesHide child attributes
benchmarkobjectShow child attributesHide child attributes
freshnessmap of objectShow child attributesHide child attributes
stale_platformsarray of stringsnotestring
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found429rate_limited500internal_error
Retrieve an episode transcript
/v1/shows/{show_id}/episodes/{episode_id}/transcriptThe best text available for an episode. Listener stores no transcripts, so status is description-fallback (the episode description, up to 9,000 characters) or missing; transcript text saved on a linked campaign's air check is returned in aircheck_excerpts. Do not present the description as a transcript.
SDKlistener.shows.episodes.transcript()client.shows.episodes.transcript()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired - Episode id (see GET /v1/shows/{show_id}/episodes).
episode_idstringrequired
Returns
200OK
- The minimal show reference embedded in cross-show results.
showobjectrequiredShow child attributesHide child attributes
episode_idstringrequiredtitlestringrequiredstatusstringrequiredOne ofdescription-fallbackmissingcomputed_atstringrequiredcache_age_secondsnumberrequiredobjectstringrequiredpublished_atstring- Description text (there is no stored transcript); capped at 9,000 characters.
textstring truncatedbooleanDefault
falsecharacter_countintegerDefault
0- Transcript text found on linked campaigns' air-check analyses, when any.
aircheck_excerptsarray of objectsShow child attributesHide child attributes
share_urlstringnotestring
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found429rate_limited500internal_error
Search episodes
/v1/episodes/searchSearch episodes by title, description, episode number or date across the workspace's shows; each hit carries its show, reach fields and cluster id. Real feed episodes rank above manual and synthetic rows. Pass show_ids to keep it fast on large networks. Results are not paginated; limit caps them.
SDKlistener.episodes.search()client.episodes.search()
Query parameters
- Search text.
querystringrequired - Limit to these show ids (default: every show in the workspace). Repeat the parameter or comma-separate values.
show_idsarray of strings - Maximum number of items to return.
limitintegerDefault
20
Returns
200OK
objectstringrequiredurlstringrequireddataarray of objectsrequiredShow child attributesHide child attributes
has_morebooleanrequired- Pass as
next_cursorstringrequiredcursorto get the next page; null on the last page. - The result's non-list fields (window, coverage, freshness, totals, note …).
metaobjectrequiredShow child attributesHide child attributes
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found429rate_limited500internal_error
Set episode goals
/v1/shows/{show_id}/episode-goalsSet the show's episode reach goals: a default target plus per-series overrides in by_series (keyed by series tag). Targets accept integers or shorthand ("250k", "1.2M"); only positive values are kept. clear=true, or no positive target at all, removes the goals.
- Send
"dry_run": trueto get{"object": "dry_run", "would_write": …}without writing anything.
SDKlistener.shows.setEpisodeGoals()client.shows.set_episode_goals()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired
Headers
- Any unique string (≤ 255 chars). Replays within 24 h return the stored response with Idempotent-Replayed: true.
Idempotency-Keystring
Request body
application/json- Reach targets; accept ints or shorthand strings like "250k", "1.2M", "1,200,000".
defaultobjectShow child attributesHide child attributes
by_seriesmap of objectShow child attributesHide child attributes
clearbooleanDefault
false- true returns exactly what would be written without writing anything (the API's test mode).
dry_runbooleanDefault
false
Returns
200OK
One of:
WriteResult
DryRun
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found409confirmation_required413body_too_large429rate_limited500internal_error
Set Substack podcast downloads for an episode node
/v1/shows/{show_id}/substack/downloadsSet the podcast downloads on one Substack card by hand (the app's "Edit metrics"), or remove that override with clear=true. The figure is stored beside Substack's API count, counts in the cluster's audio reach and wins over an imported figure until cleared. node_id is a Substack post node from GET /v1/shows/{show_id}/clusters/{cluster_id} (its podcast_downloads_source is manual, export or api). For many episodes at once use POST /v1/shows/{show_id}/substack/imports.
- Send
"dry_run": trueto get{"object": "dry_run", "would_write": …}without writing anything.
SDKlistener.shows.substack.setDownloads()client.shows.substack.set_downloads()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired
Headers
- Any unique string (≤ 255 chars). Replays within 24 h return the stored response with Idempotent-Replayed: true.
Idempotency-Keystring
Request body
application/json- Cluster id (see GET /v1/clusters).
cluster_idstringrequired - Cluster node id.
node_idstringrequired downloadsintegerclearbooleanDefault
false- true returns exactly what would be written without writing anything (the API's test mode).
dry_runbooleanDefault
false
Returns
200OK
One of:
WriteResult
DryRun
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found409confirmation_required413body_too_large429rate_limited500internal_error
Import Substack episode stats (CSV)
/v1/shows/{show_id}/substack/importsImport Substack's podcast "episode stats" CSV for a show: each row's Total becomes the downloads on that episode's Substack cards (source export) and in cluster audio reach. Substack's API only reports the downloads Substack tracks itself (often ~70 % of the export), so this brings in the publisher's full figure.
csv_text is the whole exported file (columns Title, Date, Downloads (first 30d), Total, …); rows match posts on publish time to the second, then title. Re-importing is safe. Hand-set figures still win. Send it with "dry_run": true first and review each cluster's before → after.
- Send
"dry_run": trueto get{"object": "dry_run", "would_write": …}without writing anything.
SDKlistener.shows.substack.importStats()client.shows.substack.import_stats()
Path parameters
- A show id in this workspace (see GET /v1/shows).
show_idstringrequired
Headers
- Any unique string (≤ 255 chars). Replays within 24 h return the stored response with Idempotent-Replayed: true.
Idempotency-Keystring
Request body
application/jsoncsv_textstringrequiredfile_namestring- true returns exactly what would be written without writing anything (the API's test mode).
dry_runbooleanDefault
false
Returns
200OK
One of:
WriteResult
DryRun
Errors
400parameter_invalid401credential_invalid403scope_missing404resource_not_found409confirmation_required413body_too_large429rate_limited500internal_error