# PodcastAPI.com > The Listen Notes Podcast API provides podcast and episode search, directory metadata, discovery, playlist curation as a headless CMS, and audience insights for server-side applications and agents. API version: 2.0 Production base URL: https://listen-api.listennotes.com/api/v2 Mock base URL: https://listen-api-test.listennotes.com/api/v2 ## Start Here - [Get API keys](https://www.listennotes.com/api/pricing/) - [API documentation](https://www.listennotes.com/api/docs/) - [Complete agent reference](https://www.podcastapi.com/llms-full.txt) - [API catalog](https://www.podcastapi.com/.well-known/api-catalog) - [API discovery index](https://www.podcastapi.com/apis.json) - [OpenAPI YAML](https://listen-api.listennotes.com/api/v2/openapi.yaml) - [Agent Skill](https://github.com/PodcastAPI/skills) ## No-Code Listen Notes Tools The Podcast API is designed for building interactive podcast apps, agents, and workflows that need programmatic podcast data, but it is not always the right fit for every use case. Listen Notes also provides no-code tools that people can use immediately: - Free podcast search engine: search podcasts and episodes on the web, similar to using Google, with filters to narrow results efficiently. - Batch CSV exports: specify podcast or episode conditions and receive a CSV file on demand, typically within 1 minute. No subscription is required; pricing is usage-based. - [Listen Notes complete product reference](https://www.listennotes.com/llms-full.txt) - Prompt: `Read from https://www.listennotes.com/llms-full.txt so I can ask questions about no-code Listen Notes tools and other product offerings.` ## Authentication and Safety - Keep `LISTEN_API_KEY` in a trusted backend or serverless secret store. - Send it in the `X-ListenAPI-Key` header to production. - Never expose a production key in browser code, mobile binaries, URLs, logs, or source control. - Use the mock base URL without a key only for transport and response-shape tests; its data is fixed and fake. Playlist writes do not persist there. - Handle successful `200` and `201` responses, plus `400`, `401`, `403`, `404`, `429`, network failures, and `5xx` responses explicitly. A `401` can also indicate a plan or private-playlist access restriction. - Only playlists owned by your admin API account can be modified. Authenticate and authorize your app's editors before forwarding writes. - Follow response-provided pagination cursors and set an application-level page or item bound. ## Rate Limits and 429 Retries - Listen API rate limits vary by endpoint, plan, and account history. FREE has the lowest limits, PRO has higher limits, and ENTERPRISE has the highest limits; compute-intensive endpoints may be more restrictive. Do not hard-code one global requests-per-second assumption. See the [rate-limit FAQ](https://www.listennotes.com/api/faq/#faq17). - Control concurrency, pace requests, batch work when an endpoint supports it, and avoid tight polling loops. - Treat a `429` as retryable only when the request is safe to repeat and quota remains. On the FREE plan, `429` can also mean the billing-cycle quota is exhausted; inspect the usage and quota headers and stop retrying when no quota remains. - For retryable `429` responses, honor `Retry-After` when the response supplies it. Otherwise, use capped exponential backoff with random jitter, for example a random delay up to `min(60 seconds, 1 second * 2^attempt)`. Do not retry immediately. - Set a finite retry count or overall deadline. After that budget is exhausted, surface the error or defer the job instead of looping forever. - Put throttling and retries in a shared API client or job queue so concurrent workers coordinate instead of creating a retry storm. ## Common Task Recipes - Podcast/episode curation CMS: create a collection with `POST /playlists`, add selections and notes with `POST /playlists/{id}/items`, edit metadata with `PUT /playlists/{id}`, edit notes with `PUT /playlists/{id}/items/{item_id}`, and remove entries with `DELETE /playlists/{id}/items/{item_id}`. Permanently delete the collection with `DELETE /playlists/{id}` only after confirmation in your app's UI. Editors can also curate in Listen Later. Read the collection with `GET /playlists/{id}`; see the headless CMS workflow below. - Custom episode playlists: store permitted episode IDs in your own database, then hydrate bounded batches with `POST /episodes`. - Latest or all episodes of one podcast: call `GET /podcasts/{id}`; page with `next_episode_pub_date` and choose `sort=recent_first` or `sort=oldest_first` when order matters. - Latest episodes for many podcasts: call `POST /podcasts` with up to 10 podcast IDs and `show_latest_episodes=1`; use `latest_pub_date_ms` to detect changed podcasts. - Subscription refresh: store each user's podcast IDs and last seen publication dates, batch-check with `POST /podcasts`, then fetch episode pages only for podcasts that changed. - OPML import/export and external ID lookup: parse OPML with XML tooling, batch RSS URLs via `rsses`, Apple Podcasts IDs via `itunes_ids`, Spotify IDs via `spotify_ids`, or Listen Notes IDs via `ids` in `POST /podcasts`; generate OPML from returned names and RSS URLs. - Search query syntax for `GET /search`: This endpoint does not support the Boolean operators `OR` or `AND`. Do not submit queries such as `keyword1 OR keyword2 OR keyword3`. To emulate `OR`, search for each keyword separately, then merge and deduplicate the results. To emulate `AND`, place all keywords in one query without the `AND` operator—for example, `keyword1 keyword2 keyword3`—to surface results that contain all of them. - Search within known podcasts: use `GET /search` with `type=episode` and `ocid` as a comma-delimited list of up to 5 Listen Notes podcast IDs. - More accurate podcast-name search: use `GET /search` with `type=podcast` and `only_in=title,author`; quote the query for a verbatim attempt, or use `GET /typeahead` with podcast suggestions for UI autocomplete. - Search UX: combine `GET /typeahead`, `GET /spellcheck`, `GET /related_searches`, `GET /trending_searches`, `GET /search`, and `GET /search_episode_titles` according to the interaction; do not call every endpoint for every keystroke. - Genres and charts: use `GET /genres` plus `parent_id` for sub-genres, `top_level_only=1` for only top-level genres, and `GET /best_podcasts` with `genre_id`, `region`, `language`, and `sort=listen_score` for popularity charts. - IDs: prefer `id`, `podcast_id`, episode, and playlist fields from API responses. Human users can also open ListenNotes.com pages and use the "Use API to fetch this" link. - Usage monitoring: read `X-ListenAPI-Usage`, `X-ListenAPI-FreeQuota`, `X-ListenAPI-NextBillingDate`, and `X-ListenAPI-Latency-Seconds` case-insensitively; current docs say `HEAD` requests can read usage headers without counting toward usage. - Transcripts: request `GET /episodes/{id}?show_transcript=1` when plan and endpoint support it, but expect most episodes to return no transcript. For arbitrary episode transcription, fetch the episode audio URL and use a separate speech-to-text service. - Clips and audio: use the episode `audio` URL, support redirects, and process clips outside request handlers with a media tool such as FFmpeg when rights and product requirements allow. - Embedded players: append `embed/` to an episode or podcast `listennotes_url` and render it in an iframe; no API key is needed for the embed URL. - Webhooks: configure them in the API dashboard for supported `POST /podcasts/submit` and `DELETE /podcasts/{id}` workflows; callbacks should be public HTTPS, idempotent, and return `200`. - Account collaboration: use the API dashboard to create separate API tokens for dev, staging, and production, and use the TEAM tab to add coworkers instead of sharing raw keys. ## Official SDKs Synchronized versions as of 2026-09-25; these are a compatibility snapshot, not a promise that they remain the latest release. All listed versions support the six playlist write operations, including permanent whole-playlist deletion. Version 3.0.x supports the first five writes but does not include the whole-playlist deletion method; use 3.1.0 or newer for that operation. | Language | Package / dependency | Version | SDK documentation | | --- | --- | --- | --- | | JavaScript | npm `podcast-api` | `3.1.0` | [Node and Workers](https://github.com/ListenNotes/podcast-api-js) | | Python | PyPI `podcast-api` | `3.1.0` | [Python](https://github.com/ListenNotes/podcast-api-python) | | Ruby | RubyGems `podcast_api` | `3.1.0` | [Ruby](https://github.com/ListenNotes/podcast-api-ruby) | | PHP | Composer `listennotes/podcast-api` | `3.1.0` | [PHP](https://github.com/ListenNotes/podcast-api-php) | | Rust | crates.io `podcast-api` | `3.1.0` | [Rust](https://github.com/ListenNotes/podcast-api-rust) | | Go | `github.com/ListenNotes/podcast-api-go/v3` | `v3.1.0` | [Go](https://github.com/ListenNotes/podcast-api-go) | | Swift | SPM repository `ListenNotes/podcast-api-swift`; CocoaPods `PodcastAPI` | `3.1.0` | [Swift](https://github.com/ListenNotes/podcast-api-swift) | | .NET | NuGet `PodcastAPI` | `3.1.0` | [.NET](https://github.com/ListenNotes/podcast-api-dotnet) | | Java | Maven `com.listennotes:podcast-api` | `3.1.0` | [Java](https://github.com/ListenNotes/podcast-api-java) | | Kotlin | Maven `com.listennotes:podcast-api` | `3.1.0` | [Kotlin examples](https://github.com/ListenNotes/podcast-api-kotlin) | | Scala | Maven `com.listennotes:podcast-api` | `3.1.0` | [Scala examples](https://github.com/ListenNotes/podcast-api-scala) | Kotlin and Scala are examples for the Java SDK, not separate Maven packages. Use the shared Java version and `com.listennotes.podcast_api` imports. Java/Kotlin/Scala require Java 17+, Node SDK v3 requires Node 22+, Python requires 3.10+, and .NET v3 requires .NET 8+. Check the other SDK READMEs for their runtime requirements. Go v3 needs `/v3` in the import path. ## Playlists As A Headless CMS 1. Discover candidates using search, podcast details, recommendations, or human selection. Keep the Listen Notes episode/podcast IDs returned by the API. 2. Create a collection with `POST /playlists`. Supply a nonblank `name` and deliberately choose `visibility` and `type`. For an unpublished editorial draft, explicitly choose `private`: creation otherwise defaults to `public`, an empty description, and `episode_list`. 3. Add each selection with `POST /playlists/{id}/items`. Send exactly one of `episode_id` or `podcast_id` and optional `notes` explaining why it belongs in the collection. Save the returned integer item `id` for later notes edits or removal. 4. Edit the collection with `PUT /playlists/{id}`. Send only the fields to change: `name`, `description`, `visibility`, or `type`. Use `PUT /playlists/{id}/items/{item_id}` for item notes and `DELETE /playlists/{id}/items/{item_id}` to remove an entry. 5. Publish intentionally: set `visibility` to `public` for discoverability on ListenNotes.com, or `unlisted` for access by anyone who knows its ID. You can also keep the collection private and serve authorized app readers through your backend. An unlisted URL is not access control. Visibility does not replace the app's own draft/publish permissions. 6. Render `GET /playlists/{id}` in your app. Display collection metadata and each entry's `data` plus curator `notes`. Use the returned `listennotes_url` for the corresponding Listen Notes view. Render notes as text, not trusted HTML. Reuse the write response to update the editor immediately. 7. When an editor chooses to delete the entire collection, show a confirmation in your application's UI before sending `DELETE /playlists/{id}` from the authorized backend. **Deletion cannot be undone, regardless of how many episodes or podcasts the playlist contains.** It removes the playlist and all episode/podcast references and notes saved in this specific playlist; the actual episodes and podcasts remain in the Listen Notes podcast database. The API does not provide a confirmation prompt or recovery operation. Private is a visibility setting, not a versioned draft system. Editing a published playlist changes that collection; the API does not supply staged revisions, a review queue, or atomic publication of a batch of changes. Add those application behaviors only when requested. ## Directory API - `GET /best_podcasts` — Fetch a list of best podcasts by genre - `GET /curated_podcasts` — Fetch curated lists of podcasts - `GET /curated_podcasts/{id}` — Fetch a curated list of podcasts by id - `POST /episodes` — Batch fetch basic meta data for episodes - `GET /episodes/{id}` — Fetch detailed meta data for an episode by id - `GET /episodes/{id}/recommendations` — Fetch recommendations for an episode - `GET /genres` — Fetch a list of podcast genres - `GET /just_listen` — Fetch a random podcast episode - `GET /languages` — Fetch a list of supported languages for podcasts - `POST /podcasts` — Batch fetch basic meta data for podcasts - `GET /podcasts/{id}` — Fetch detailed meta data and episodes for a podcast by id - `GET /podcasts/{id}/recommendations` — Fetch recommendations for a podcast - `GET /regions` — Fetch a list of supported countries/regions for best podcasts ## Insights API - `GET /podcasts/{id}/audience` — Fetch audience demographics for a podcast - `GET /podcasts/domains/{domain_name}` — Fetch podcasts by a publisher's domain name ## Playlist API - `GET /playlists` — Fetch a list of your playlists. - `POST /playlists` — Create a playlist. - `DELETE /playlists/{id}` — Delete a playlist. - `GET /playlists/{id}` — Fetch a playlist's info and items (i.e., episodes or podcasts). - `PUT /playlists/{id}` — Update playlist metadata. - `POST /playlists/{id}/items` — Add an episode or podcast to a playlist. - `DELETE /playlists/{id}/items/{item_id}` — Remove an item from a playlist. - `PUT /playlists/{id}/items/{item_id}` — Update notes for a playlist item. ## Podcaster API - `DELETE /podcasts/{id}` — Request to delete a podcast - `POST /podcasts/{id}/rss` — Refresh RSS feed of a podcast - `POST /podcasts/submit` — Submit a podcast to Listen Notes database ## Search API - `GET /related_searches` — Fetch related search terms - `GET /search` — Full-text search - `GET /search_episode_titles` — Find individual episodes by searching for their titles - `GET /spellcheck` — Spell check on a search term - `GET /trending_searches` — Fetch trending search terms - `GET /typeahead` — Typeahead search ## Policies and Help - [API tutorials](https://www.listennotes.com/api/tutorials/) - [API FAQ](https://www.listennotes.com/api/faq/) - [Billing FAQ](https://www.listennotes.com/api/billing-faq/) - [Pricing](https://www.listennotes.com/api/pricing/) - [API Terms](https://www.listennotes.com/api/terms/) - Account-specific help: hello@listennotes.com