Skip to content
ThemeNord

Same themes as the MinusPod app

Default

Catppuccin

Dracula

Nord

Gruvbox

Solarized

Rose Pine

Kanagawa

Ayu

Other

Feeds

Podcast feed management

List all feeds

Returns configured podcast feeds with metadata. Omitting page and limit still returns every feed, with pagination fields describing that unbounded page; passing either one switches to a paginated page. Set includeLatestEpisodes=true to add a bounded latestEpisodes projection to each feed, computed in one query for the whole page rather than one request per feed.

  • page (query, integer): Page number (1-based). Only takes effect when page or limit is set; otherwise every feed is returned.
  • limit (query, integer): Feeds per page. Only takes effect when page or limit is set.
  • includeLatestEpisodes (query, boolean): When true, add a latestEpisodes projection to each feed.
  • episodesPerFeed (query, integer): Maximum episodes per feed in latestEpisodes. Clamped to 1-20.
  • sortBy (query, string, one of recent, title): Orders the whole feed list before it is sliced into a page, so a page is a slice of the sorted list rather than a sorted slice. recent orders by the feed’s newest episode, title alphabetically (case-insensitive). Any other value is a 400.
  • sortDir (query, string, one of asc, desc): Sort direction. Defaults to desc for recent and asc for title. Any other value is a 400.
Status Description Body
200 List of feeds object
400 Unknown sortBy or sortDir
  • feeds (array of Feed)
  • total (integer): Total feed count.
  • totalPages (integer)
  • page (integer)
  • limit (integer)
  • offset (integer)
  • lastRefreshCompletedAt (string or null (date-time)): When an all-feeds refresh pass last finished (15-minute scheduler or the manual Refresh All action). Null until the first pass completes.

Add a new feed

Add a new podcast feed. Three shapes: a subscribed feed (default), which requires sourceUrl and fetches/parses it before saving; a local (archive-import) feed, set with feedType: “local”, which takes no sourceUrl and no upstream is ever fetched: metadata comes entirely from the request body; or the single combined recents feed, feedType: “recents”, served at /recents with a fixed slug, taking only title and description (409 when one already exists). The local branch still validates slug (or derives one from title) but skips URL/SSRF validation since there is no URL.

  • downloadUserAgentOverride (string or null): Per-feed download User-Agent. Printable ASCII only. Null or blank inherits downloadUserAgent.
  • feedUserAgentOverride (string or null): Per-feed RSS User-Agent. Printable ASCII only. Null or blank inherits feedUserAgent.
  • sourceUrl (string (uri)): URL of the source RSS feed. Required unless feedType is “local”.
  • slug (string): Optional custom slug (auto-generated if not provided). Immutable once the feed is created.
  • feedType (string, one of subscribed, local, recents, youtube): “local” creates an archive-import feed with no upstream RSS: title is required, sourceUrl is ignored, and no fetch happens. “youtube” creates a feed from a YouTube playlist or channel: sourceKind, sourceId and title are required, sourceUrl is ignored, and the first listing runs before the response. Omit or “subscribed” for a normal feed. Default subscribed.
  • sourceKind (string, one of playlist, channel): YouTube feeds only. Kind of the source.
  • sourceId (string): YouTube feeds only. Canonical playlist id or channel id, as returned by the preview.
  • artworkUrl (string (uri)): YouTube feeds only. Cover image downloaded once at creation.
  • includeShorts (boolean or null): YouTube feeds only. Whether videos of 180 seconds or less are listed; null follows the default.
  • autoProcessOverride (boolean or null): Per-feed auto-process override applied at creation. Null inherits the global setting.
  • title (string): Feed title. Required and editable when feedType is “local”; ignored for a subscribed feed, which takes its title from the upstream RSS on refresh.
  • description (string): Feed description. Local feeds only; ignored for a subscribed feed.
  • author (string or null): itunes:author. Local feeds only.
  • explicit (boolean or null): itunes:explicit. Local feeds only; null means unset.
  • categories (array of string): itunes:category list. Local feeds only; null clears.
  • p20 (LocalFeedP20)
  • maxEpisodes (integer or null): Per-feed cap on served episode count. Subscribed feeds: clamped to 10-500; omit or set null to fall back to the global maxFeedEpisodes setting (default 300). Local feeds: 0, null, or omitted serves every episode (the default); a positive value up to 10000 serves only the newest N.
  • onlyExposeProcessedEpisodes (boolean or null): Per-feed override. true hides non-processed episodes; false shows everything; null falls back to the global onlyExposeProcessedDefault setting.
  • processingMode (string, one of standard, keep_content, skip_detection, passthrough): Processing mode applied before the first refresh. Subscribed and YouTube feeds only; local and recents feeds reject it with a 400. Omitted means standard. cue_only is rejected on create because it needs cue templates; set it from PATCH /feeds/{slug} afterwards.
  • requireManualApproval (boolean or null): Per-feed override. true keeps newly processed episodes out of the served feed until approved; false publishes them at once; null falls back to the global requireManualApprovalDefault setting.
  • retentionDaysOverride (integer or null): Per-feed retention override. Null falls back to the global retentionDays setting; 0 archives the feed so processed audio is never deleted, including by the force-all cleanup; 1-3650 keeps it for that many days.
  • audioReplacementSoundOverride (boolean or null): Override replacement sound for this feed; null inherits the global choice.
  • audioMp3StreamCopyOverride (boolean or null): Override MP3 stream copy for this feed; null inherits the global choice.
  • keepOriginalAudioOverride (boolean or null): Per-feed override for retaining the pre-cut original audio. Null falls back to the global keepOriginalAudio setting; true always keeps it; false never does. Applies from the next episode processed.
Status Description Body
201 Feed created successfully object
400 Bad request - invalid input Error
409 Feed with slug already exists Error
  • slug (string)
  • sourceUrl (string)
  • feedUrl (string)
  • message (string)

Import feeds from OPML file

Import podcast feeds from an OPML file upload. Accepts .opml or .xml files. Automatically generates slugs from feed titles and refreshes the first 5 imported feeds.

Request body (multipart/form-data, required)

Section titled “Request body (multipart/form-data, required)”
  • opml (string (binary), required): OPML file (.opml or .xml)
Status Description Body
200 No feeds were imported (all skipped or failed)
201 Feeds imported successfully object
400 Invalid OPML file or no file provided Error
  • imported (integer): Number of feeds successfully imported
  • skipped (integer): Number of feeds skipped (already exist)
  • failed (integer): Number of feeds that failed to import
  • feeds (object)
  • feeds.imported (array of object)
  • feeds.imported[].url (string)
  • feeds.imported[].slug (string)
  • feeds.skipped (array of object)
  • feeds.skipped[].url (string)
  • feeds.skipped[].slug (string)
  • feeds.skipped[].reason (string)
  • feeds.failed (array of object)
  • feeds.failed[].url (string)
  • feeds.failed[].error (string)

Export feeds as OPML file

Export all subscribed podcast feeds as an OPML XML file. Use mode=original for upstream source URLs (backup/migration). Use mode=modified for MinusPod-served ad-free feed URLs (import into podcast apps).

  • mode (query, string, one of original, modified): URL mode: “original” for upstream source URLs, “modified” for MinusPod ad-free feed URLs
  • slugs (query, string): Optional comma-separated feed slugs to include (in the usual feed order). Unknown slugs are skipped. Omit to export every feed.
Status Description Body
200 OPML file download application/octet-stream
400 Invalid mode parameter, or slugs matched no feeds Error

Export selected feeds as an OPML file

Export selected feeds in the usual feed order. Unknown slugs are skipped; the request fails if none match.

  • mode (query, string, one of original, modified): URL mode: “original” for upstream source URLs, “modified” for MinusPod ad-free feed URLs
  • slugs (array of string, required)
Status Description Body
200 OPML file download application/octet-stream
400 Invalid mode or slug list, or slugs matched no feeds Error

OPML feed list for podcast apps’ import-from-URL

App-level, key-gated OPML export served from the public feed domain so podcast apps can import feeds directly by URL. Requires authenticated feeds to be enabled and a valid feed key; returns 404 when feed auth is disabled (the modified list is a bundle of keyed feed URLs and is never served unauthenticated). The copyable URLs are surfaced by GET /settings as opmlModifiedUrl / opmlOriginalUrl.

  • mode (path, string, one of modified, original, required): modified = MinusPod ad-free feed URLs; original = upstream source URLs
  • key (query, string, required): The global feed auth key
Status Description Body
200 OPML document text/xml
401 Missing or invalid feed key
404 Feed auth disabled, or unknown mode

Get a single feed

Returns details for a specific podcast feed

  • slug (path, string, required): Podcast feed slug identifier
Status Description Body
200 Feed details Feed
404 Resource not found Error

Update feed settings

Update podcast feed settings like network override, DAI platform, processing overrides, and the source RSS URL. The recents feed accepts only title and description; any other field returns 400.

  • slug (path, string, required): Podcast feed slug identifier
  • sourceUrl (string (uri)): Replacement source RSS URL for this feed. The server fetches and parses the URL before persisting; a URL that does not return a parseable RSS feed is rejected with 400 and nothing is saved. On success the stored ETag/Last-Modified validators are cleared and an immediate forced refresh runs. Existing episodes are kept (matched by GUID). Cannot be null or empty.
  • networkIdOverride (string or null): Network to assign this feed to: a known network id, or a custom name that links feeds sharing the same value (null uses the auto-detected network). The effective network is the override when set, else the auto-detected one.
  • daiPlatform (string): DAI platform identifier (e.g., megaphone, acast)
  • autoProcessOverride (boolean or null): Override auto-process setting (null uses global)
  • autoProcessMaxAgeHoursOverride (integer or null): Per-feed auto-process window in hours (null uses the global autoProcessMaxAgeHours)
  • downloadUserAgentOverride (string or null): Audio, artwork, chapters, and transcript User-Agent for this feed. Printable ASCII only. Null or blank inherits downloadUserAgent. Cross-fetch uses a different podcast client.
  • feedUserAgentOverride (string or null): RSS fetch User-Agent for this feed. Printable ASCII only. Null or blank inherits feedUserAgent.
  • languageOverride (string or null): Per-feed transcription language. ‘auto’ pins auto-detect for this feed; a language code (e.g. ‘en’, ‘de’) forces that language; null falls back to the global whisperLanguage setting.
  • titleOverride (string or null): Per-feed display title shown to subscribers in the generated RSS feed (issue 375). Survives RSS refreshes. Null or empty clears it and falls back to the source feed title.
  • descriptionOverride (string or null): Per-feed description shown to subscribers in the generated RSS feed. Survives RSS refreshes. Line breaks are kept. Null or empty clears it and falls back to the source feed description.
  • detectionNotes (string or null): Operator hints about this show appended to the LLM ad-detection and review prompts (issue 709). Survives RSS refreshes. Null or empty clears it.
  • chapterNotes (string or null): Per-feed notes sent as a final Feed notes paragraph with every chapter generation request. Null or blank clears it.
  • detectionMode (string or null, one of blacklist, keep_content, null): Per-feed ad-detection mode. ‘keep_content’ (experimental) has the LLM label show content and removes everything else; null or ‘blacklist’ is the default, which labels and removes ads. Prefer processingMode; kept for per-field compatibility.
  • chaptersMode (string or null, one of auto, generate, off, null): Per-feed chapters mode. ‘auto’ preserves publisher-embedded chapters when enough survive the cut, otherwise generates them; ‘generate’ always generates new chapters; ‘off’ skips the chapter step entirely; null follows the global chaptersMode setting.
  • chaptersInNotes (string or null, one of on, off, null): Per-feed override for listing generated chapters in served episode descriptions. null follows the global chaptersInNotes setting.
  • reviewLinksInNotes (string or null, one of on, off, null): Per-feed override for review and rate links in served episode descriptions. null follows the global reviewLinksInNotes setting.
  • adChaptersEnabled (boolean or string or null, one of true, false, on, off, null): Deprecated. Translates into segmentCategoryActions; false (or ‘off’) demotes every mark to keep. true, ‘on’, and null are accepted and ignored (null is a no-op, matching the old per-feed override contract).
  • adChapterCategories (map of boolean): Deprecated. Translates into segmentCategoryActions; true promotes keep to mark, false demotes mark to keep; remove and beep stay unchanged. null is a no-op.
  • queuePriority (string or null, one of high, normal, low, null): Per-feed auto-process queue priority (issue 625). ‘high’ processes this feed’s episodes before other queued episodes; ‘low’ runs only when nothing else is waiting; ‘normal’ or null uses the default ordering. Changing it re-stamps this feed’s already-queued pending episodes immediately.
  • lowAdYieldAction (string or null, one of nothing, redetect, reprocess, full, null): Per-feed override of the global lowAdYieldAction setting; null uses the global value. Automatic response when a pipeline-initiated run removes far less ad time than the feed’s recent average: ‘nothing’ (default), ‘redetect’ (LLM-only rerun from the stored transcript), ‘reprocess’, or ‘full’. Fires at most once per episode.
  • episodeLogs (string or null, one of on, off, null): Per-feed run log storage (issue 660): ‘on’ stores each run’s pipeline log, ‘off’ never does, null follows the global setting. Nothing is stored while episodeLogRetentionDays is 0.
  • titleSkipPatterns (array of string): Per-feed episode title blacklist. Each pattern is matched against the whole episode title, case-insensitively (fnmatch glob); use ‘*’ as a wildcard, e.g. ‘Bonus Episode ’ matches any title starting with ‘Bonus Episode’. Without a wildcard the whole title must match, so a plain substring needs surrounding ‘’ wildcards. A matching episode is never queued from RSS refresh or JIT-processed; requests for a skipped episode’s audio redirect to the upstream enclosure instead. Null or an empty array clears the blacklist.
  • descriptionTrimPattern (string or null): Chapter title glob for the chapter trim. Matched against the title of each timestamp line in the episode description and against the episode’s chapters (upstream or MinusPod-generated), case-insensitively, with ‘*’ as a wildcard. A match cuts from that timestamp per descriptionTrimMode. Null clears the rule.
  • descriptionTrimMode (string, one of to_end, to_next): to_end (default) cuts to the end of the episode; to_next cuts until the next timestamp line.
  • descriptionSkipPatterns (array of string): Per-feed episode description blacklist (issue 835). Each pattern is matched against the plain-text description (HTML tags removed, whitespace collapsed), case-insensitively (fnmatch glob); use ‘’ as a wildcard, e.g. ‘This is a preview. To hear the entire episode’. Without a wildcard the whole description must match, so a plain substring needs surrounding ‘’ wildcards. A matching episode is never queued from RSS refresh or JIT-processed; requests for a skipped episode’s audio redirect to the upstream enclosure instead. Null or an empty array clears the blacklist.
  • titleSkipAction (string or null, one of serve_original, hide, null): Served-RSS handling for an episode skipped by title, description, or duration. ‘serve_original’ (default, null) keeps original audio available; ‘hide’ removes the entry.
  • minDurationSeconds (number or null): Minimum publisher RSS duration in seconds, inclusive. Null clears this limit; omission preserves it. The effective minimum cannot exceed the maximum. Unknown or zero durations remain eligible; manual reprocessing overrides the filter.
  • maxDurationSeconds (number or null): Maximum publisher RSS duration in seconds, inclusive. Null clears this limit; omission preserves it. The effective maximum cannot be below the minimum. Filtering uses RSS duration before ad removal.
  • cueTemplateScoreOverride (number or null): Per-feed ZNCC match threshold for audio cue template matching. Overrides the global audioCueTemplateScore setting for this feed. null or omitted clears the override and falls back to the global setting.
  • cueCreateFromPairsOverride (boolean or null): Per-feed override for cue-pair ad synthesis. true forces on, false forces off, null inherits the global audio_cue_create_from_pairs setting.
  • cueCutMatchesOverride (boolean or null): Per-feed override for cutting matched cue audio. true forces on, false forces off, null inherits the global audio_cue_cut_matches setting.
  • cuePairMinBreakOverride (number or null): Per-feed minimum break duration (seconds) for cue-pair synthesis. null inherits the global setting.
  • cuePairMaxBreakOverride (number or null): Per-feed maximum break duration (seconds) for cue-pair synthesis. null inherits the global setting.
  • cuePairMaxBreakFractionOverride (number or null): Per-feed maximum break fraction of episode duration for cue-pair synthesis. null inherits the global setting.
  • cueSnapConfidenceOverride (number or null): Per-feed minimum cue confidence to snap an ad edge. null inherits the global audio_cue_snap_confidence setting.
  • cueSnapLeadOverride (number or null): Per-feed snap lead window (seconds) before an ad edge. null inherits the global audio_cue_snap_lead_seconds setting.
  • cueSnapLagOverride (number or null): Per-feed snap lag window (seconds) after an ad edge. null inherits the global audio_cue_snap_lag_seconds setting.
  • silenceSnapEnabled (boolean or null): Per-feed opt-in for snapping cut boundaries to nearby silence. Simple flag, not tri-state; null and false both read as off.
  • transitionSnapEnabled (boolean or null): Per-feed opt-in for snapping cut boundaries to content-transition cues. Simple flag, not tri-state; null and false both read as off.
  • spliceVetoEnabled (boolean or null): Per-feed splice check. Tri-state: null inherits the global spliceVetoEnabled setting, true forces the check on, false lets long cuts through without splice evidence.
  • maxAdDurationOverride (number or null): Per-feed max ad duration cap in seconds. Ads longer than this are held for review instead of cut. null means no cap (global MAX_AD_DURATION constants apply). Also raises the longest single detection the model may report for this feed (the global Longest single LLM detection, default 7 minutes).
  • adDetectionExcludeStartOverride (number or null): Per-feed opening window in seconds during which ad markers are ignored. null inherits adDetectionExcludeStartSeconds, 0 disables it for the feed, 1 to 600 sets the feed’s own window.
  • maxAdDurationRejectOverride (number or null): Per-feed length past which an ad must name a recognized sponsor to be cut; one that does not is held for review. Must not exceed the global maxAdDurationConfirmedSeconds. null falls back to the global maxAdDurationSeconds setting. Also raises the longest single detection the model may report for this feed (the global maxLlmWindowAdSeconds, default 7 minutes), so set it to the length of the show’s longest continuous ad block.
  • cueGatedApproval (boolean or null): Per-feed cue-gated approval. When true, only ads with audio cue evidence auto-cut; others are held for review. null and false both read as off.
  • differentialFetchEnabled (boolean or null): Legacy per-feed cross-fetch flag. Use differentialFetchMode for new clients; null selects automatic DAI detection.
  • processingMode (string, one of passthrough, skip_detection, keep_content, standard, cue_only): Writable processing-mode preset. Sets passthroughEnabled, skipAdDetection, and detectionMode together. Cannot be combined with those fields in one request. cue_only requires at least one enabled ad_break_start and one enabled ad_break_end template on the feed; rejected with a 400 otherwise, since a boundary-only cue cannot pair safely without the LLM pass.
  • passthroughEnabled (boolean or null): When true, episodes on this feed are downloaded and served exactly as published, with no transcription, detection, or cutting. Null and false both mean normal processing. Prefer processingMode; kept for per-field compatibility.
  • skipAdDetection (boolean or null): When true, episodes on this feed are transcribed and get chapters and a transcript, but ad detection is skipped and nothing is cut. For ad-free shows. Null and false both mean normal processing. Prefer processingMode; kept for per-field compatibility.
  • cueOnlySafety (string or null, one of hold_new, auto_cut, null): Per-feed safety policy for cue_only mode. ‘hold_new’ (default) holds a template’s synthesized cuts for review until it has matched a paired start/end cue on 3 episodes. ‘auto_cut’ cuts immediately but still holds any pair scoring below 0.90 confidence. null resets to the default ‘hold_new’ behavior. Ignored outside cue_only mode.
  • skipTranscription (boolean or null): Per-feed opt-out from transcription. Only valid on a feed already in cue_only mode; rejected with a 400 otherwise. Generated chapters stop, and transcript search and VTT subtitles become unavailable for those episodes, but publisher chapters (embedded ID3 or linked Podcasting 2.0 JSON) still get remapped onto the cut audio. Null and false both mean transcription still runs.
  • maxEpisodes (integer or null): Per-feed cap on served episode count. Subscribed feeds: clamped to 10-500; set null to fall back to the global maxFeedEpisodes setting. Local feeds: 0 or null serves every episode (the default); a positive value up to 10000 serves only the newest N.
  • onlyExposeProcessedEpisodes (boolean or null): Per-feed override. true hides non-processed episodes; false shows everything; null falls back to the global onlyExposeProcessedDefault setting.
  • requireManualApproval (boolean or null): Per-feed override. true keeps newly processed episodes out of the served feed until approved; false publishes them at once; null falls back to the global requireManualApprovalDefault setting.
  • retentionDaysOverride (integer or null): Per-feed retention override. Null falls back to the global retentionDays setting; 0 archives the feed so processed audio is never deleted, including by the force-all cleanup; 1-3650 keeps it for that many days.
  • audioReplacementSoundOverride (boolean or null): Override replacement sound for this feed; null inherits the global choice.
  • audioMp3StreamCopyOverride (boolean or null): Override MP3 stream copy for this feed; null inherits the global choice.
  • keepOriginalAudioOverride (boolean or null): Per-feed override for retaining the pre-cut original audio. Null falls back to the global keepOriginalAudio setting; true always keeps it; false never does. Applies from the next episode processed.
  • ytProcessDelayMinutesOverride (integer or null): YouTube feeds only. Minutes to wait after a video is published before processing. Null follows the global setting.
  • ytProbeAttemptsOverride (integer or null): YouTube feeds only. SponsorBlock lookup attempts. Null follows the global setting.
  • ytProbeIntervalMinutesOverride (integer or null): YouTube feeds only. Minutes between SponsorBlock lookup attempts. Null follows the global setting.
  • ytLlmFallbackOverride (boolean or null): YouTube feeds only. Run LLM detection when SponsorBlock has no data. Null follows the global setting.
  • ytLlmOnTopOverride (boolean or null): YouTube feeds only. Run LLM detection on top of SponsorBlock segments. Null follows the global setting.
  • ytCaptionsOverride (boolean or null): YouTube feeds only. Use YouTube captions as the transcript. Null follows the global setting.
  • ytHidePrivateOverride (boolean or null): YouTube feeds only. Hide private and deleted episodes from the listing. Null follows the global setting.
  • ytTranscribeOverride (boolean or null): YouTube feeds only. Transcribe with the configured transcriber when captions are missing. Null follows the global setting.
  • youtubeIncludeShorts (boolean or null): YouTube feeds only. Whether videos of 180 seconds or less are listed. Null follows the default.
  • segmentCategoryActions (map of string, one of remove, beep, keep, mark): Per-feed segment-category action overrides (issue
  • detectShowSegments (boolean or null): Per-feed opt-in to detect intro, outro, and recap/housekeeping segments in addition to the always-detected ad-side categories. true/false override the global detectShowSegments setting for this feed; null falls back to it.
  • skipSecondPass (boolean or null): When true, the pass-2 verification scan of the cut audio is skipped. Null follows the global skipSecondPass setting.
  • transcriptDifferential (boolean or null): Per-feed override for upstream-transcript differential. True enables and false disables it for this feed; null follows the global transcriptDifferentialEnabled setting.
  • differentialFetchMode (string or null, one of inherit, auto, on, off, null): Per-feed cross-fetch mode. ‘inherit’ follows the global default, ‘auto’ follows DAI detection, and ‘on’ or ‘off’ forces the stage.
  • ownEpisodeGuids (boolean or null): When true, the served RSS uses MinusPod episode ids as item GUIDs instead of passing upstream GUIDs through (issue 598). Switching it on a feed with subscribers makes podcast apps treat every episode as new once. Null and false both mean upstream GUIDs. New feeds are created with true.
  • description (string or null): Feed description, rewritten into the served channel <description>. Editable on any feed, local or subscribed, unlike title and p20 below, which are local-feed only (author, explicit and categories also work on YouTube feeds).
  • title (string): Local feeds only (issue #625); 400 on a subscribed feed, whose title is RSS-managed and would be overwritten on the next refresh anyway; use titleOverride there instead. Must be non-empty.
  • author (string or null): itunes:author. Local and YouTube feeds; 400 on a subscribed feed.
  • explicit (boolean or null): itunes:explicit. Local and YouTube feeds; 400 on a subscribed feed. Null clears.
  • categories (array of string): itunes:category list. Local and YouTube feeds; 400 on a subscribed feed. Null clears.
  • p20 (LocalFeedP20): Local feeds only; 400 on a subscribed feed. Merged onto the feed’s existing stored p20 object, so an unspecified tag is left untouched, except sending the literal JSON null, which clears the six list tags and any stored locked_owner in one shot (see LocalFeedP20). guid can never be set here.
Status Description Body
200 Feed updated successfully Feed
400 Bad request - invalid input Error
404 Resource not found Error

Delete a feed

Delete a podcast feed and all associated data

  • slug (path, string, required): Podcast feed slug identifier
Status Description Body
200 Feed deleted successfully object
404 Resource not found Error
  • message (string)
  • slug (string)

Refresh a single feed

Fetch the latest RSS feed and update the episode list. By default this sends a conditional GET. If upstream returns 304 Not Modified, the refresh is a no-op. Pass {"force": true} in the body to bypass the stored ETag / Last-Modified headers and do a full fetch, useful when an upstream CDN is falsely returning 304 against its own new content.

  • slug (path, string, required): Podcast feed slug identifier

Optional force-refresh flag. Omit for default conditional GET.

  • force (boolean): When true, clears the podcast’s stored ETag + Last-Modified values before fetching so upstream cannot short-circuit with 304 Not Modified. Default false.
Status Description Body
200 Feed refreshed successfully object
400 Feed has no upstream source Error
404 Resource not found Error
500 Internal server error Error
502 Upstream fetch failed or returned content that could not be parsed as RSS Error
  • slug (string, required)
  • message (string, required)
  • outcome (RefreshOutcome, required)
  • episodeCount (integer, required)
  • lastRefreshed (string or null (date-time), required)
  • lastPodpingAt (string or null (date-time), required)

Refresh all feeds

Refresh RSS feeds for all configured podcasts. By default this sends a conditional GET per feed. If upstream returns 304 Not Modified, that feed is a no-op. Pass {"force": true} in the body to clear every podcast’s stored ETag / Last-Modified before fetching so upstream cannot short-circuit with 304.

Optional force-refresh flag. Omit for default conditional GET per feed.

  • force (boolean): When true, clears every podcast’s stored ETag + Last-Modified values before fetching so upstream cannot short-circuit with 304 Not Modified. Default false.
Status Description Body
200 All feeds refreshed RefreshAllResult
207 Refresh pass completed with at least one feed failure RefreshAllResult
500 Internal server error Error

Refresh cover art for all feeds

Re-pull each feed’s cover art and rebuild its served RSS so the cover-art badge setting (artworkWatermarkEnabled, issue #420) takes effect. Unlike a feed refresh, this does not re-discover or queue episodes, so it never triggers processing. Podcast apps still re-fetch the feed on their own schedule before the change is visible.

Status Description Body
200 Artwork refreshed object
  • message (string)
  • feedCount (integer)

Rebuild every served RSS with current URL settings (feed auth key, cover badge, base URL)

Re-fetch each feed’s upstream source and re-render its served RSS so URL-affecting settings (feed auth key, cover-art badge, base URL) take effect. Unlike a feed refresh, this never re-discovers or queues episodes, so it cannot trigger processing. Podcast apps still re-fetch the feed on their own schedule before the change is visible.

Status Description Body
200 Feeds regenerated object
  • message (string)
  • feedCount (integer)

Get feed artwork

Returns cached podcast artwork without admin authentication. Safe legacy slugs are accepted up to 200 characters.

No session needed.

  • slug (path, string, required): Podcast feed slug identifier
Status Description Body
200 Artwork image image/jpeg, image/png
404 Resource not found Error

Get a feed’s ad-position distribution

Returns where this feed’s ad cuts have historically landed across an episode, as a normalized-position histogram plus the learned prior zones. Setting-independent: returns data even when the positional-prior experiment is disabled.

  • slug (path, string, required): Podcast feed slug identifier
Status Description Body
200 Ad distribution for the feed AdDistribution
404 Resource not found Error

List known podcast networks

Returns list of known podcast networks for network-level pattern matching

Status Description Body
200 List of networks object

List subscriber keys across all feeds

Labels and timestamps without secret values, sorted by feed title, label, then creation time.

Status Description Body
200 Subscriber keys with their feed object

List feed subscriber keys

  • slug (path, string, required): Podcast feed slug identifier
Status Description Body
200 Labels and timestamps without secret values object
404 Resource not found Error

Create a feed subscriber key

Returns the scoped token and feed URL once.

  • slug (path, string, required): Podcast feed slug identifier
  • label (string)
Status Description Body
201 Scoped token and feed URL FeedSubscriberKeyCreated
400 Bad request - invalid input Error
404 Resource not found Error

DELETE /feeds/{slug}/subscriber-keys/{key_id}

Section titled “DELETE /feeds/{slug}/subscriber-keys/{key_id}”

Revoke a feed subscriber key

  • slug (path, string, required): Podcast feed slug identifier
  • key_id (path, string, required)
Status Description Body
200 Key revoked object
404 Resource not found Error
  • revoked (constant true, required)

DELETE /feeds/{slug}/subscriber-keys/{key_id}/record

Section titled “DELETE /feeds/{slug}/subscriber-keys/{key_id}/record”

Delete a revoked subscriber key record

Removes only a record that was already revoked. The deleted token stays invalid because no matching credential remains.

  • slug (path, string, required): Podcast feed slug identifier
  • key_id (path, string, required)
Status Description Body
200 Revoked key record deleted object
404 Subscriber key not found
409 Subscriber key is still active
  • deleted (constant true, required)

List domains seen sending Podpings on the Hive chain

Diagnostic view of what the Podping listener has observed. The listener records the domain of every feed URL announced on the chain, including ones that match no local feed, which is what lets a feed report whether its host sends Podpings at all. Counts are aggregated per domain as the listener runs, so there is no per-notification history to return. Rows recorded earlier stay visible when the listener is disabled.

  • limit (query, integer): Rows to return, clamped to 1-500. Does not affect the totals.
Status Description Body
200 Observed Podping host domains, most recently active first object
  • hosts (array of object)
  • hosts[].domain (string)
  • hosts[].firstSeenAt (string (date-time))
  • hosts[].lastSeenAt (string (date-time))
  • hosts[].pingCount (integer)
  • hosts[].active (boolean): Seen within activeWindowDays.
  • limit (integer)
  • totalDomains (integer)
  • activeDomains (integer)
  • activeWindowDays (integer)
  • listenerEnabled (boolean)
  • allNodesDown (boolean): Non-fatal: every configured Hive RPC node is currently failing. RSS polling remains the fallback, so this never gates /health or feed refresh.
  • degradedSince (string or null (date-time)): When allNodesDown last became true, or null.
  • nodes (array of object): Durable per-node health, one entry per configured RPC node.
  • nodes[].node (string)
  • nodes[].selected (boolean): Last node to complete a successful RPC call.
  • nodes[].consecutiveFailures (integer)
  • nodes[].lastSuccessAt (string or null (date-time)): Last successful RPC response, shown as Last seen; null before success.
  • nodes[].nextRetryAt (string or null (date-time))
  • nodes[].lastFailureReason (string or null)
  • nodes[].httpStatus (integer or null): Latest HTTP status, including 200 with invalid_response; null if none arrived.
  • nodes[].outcome (string or null, one of healthy, http_error, invalid_response, unreachable, null): Latest RPC outcome; null before the first check.

Get a feed’s tag breakdown (rss / episode / user / effective)

  • slug (path, string, required)
Status Description Body
200 Tag breakdown object
404 Feed not found
  • effective (array of string)
  • rss (array of string)
  • episode (array of string)
  • user (array of string)

Update a feed’s user-added tags

  • slug (path, string, required)
  • user_tags (array of string, required)
Status Description Body
200 Updated tag breakdown object
400 Unknown or invalid tag(s)
  • effective (array of string)
  • rss (array of string)
  • episode (array of string)
  • user (array of string)

Re-cut every processed episode of a feed against the current segment-category action maps

Queues the existing per-episode recut (reprocess_mode=recut) for every processed episode of the feed that still has a retained original, saved transcript segments, and ad detections. Each recut re-resolves segment-category actions against the current per-feed/global maps, so this is the bulk trigger for applying a changed segment-category setting to already-processed episodes.

  • slug (path, string, required)
Status Description Body
200 Recut queued for qualifying episodes object
404 Feed not found
  • queued (integer)
  • skipped (integer)