Listen Notes Best Podcasts API

Fetch curated best-podcasts charts by genre, region, publisher region, and language - the editorial and popularity-ranked lists that power podcast discovery experiences.

OpenAPI Specification

listennotes-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: 'Listen API: Podcast Search, Directory, and Insights API'
  description: |
    Simple and no-nonsense podcast search and directory API from Listen Notes.
    Full-text search all podcasts and episodes by people, places, or topics;
    fetch podcast and episode metadata; browse best-podcasts charts, curated
    lists, and genres; retrieve recommendations; power typeahead autocomplete;
    and pull audience demographics. All requests are authenticated with an
    `X-ListenAPI-Key` request header. FREE, PRO, and ENTERPRISE plans are billed
    on a per-request basis.

    This document was authored by API Evangelist and grounded in the official
    Listen API OpenAPI specification published at
    https://listen-api.listennotes.com/api/v2/openapi.yaml. Endpoints and
    parameters reflect the published specification.
  termsOfService: https://www.listennotes.com/api/terms/
  contact:
    name: Listen Notes
    url: https://www.listennotes.com/api/
    email: hello@listennotes.com
  version: '2.0'
servers:
  - url: https://listen-api.listennotes.com/api/v2
    description: API Production Server
tags:
  - name: Search API
    description: Endpoints to search podcasts and episodes.
  - name: Directory API
    description: Endpoints to fetch podcasts, episodes, charts, and reference data.
  - name: Playlist API
    description: Endpoints to fetch Listen Later playlists data.
  - name: Podcaster API
    description: Endpoints to improve the podcast database.
  - name: Insights API
    description: Endpoints to get insights of podcasts, e.g., audience demographics.
security:
  - apiKeyHeader: []
paths:
  /search:
    get:
      tags: [Search API]
      summary: Full-text search
      description: |
        Full-text search on episodes, podcasts, or curated lists of podcasts.
        Use the `offset` parameter to paginate through results. FREE plan sees up
        to 30 results per query, PRO up to 300, ENTERPRISE up to 10,000.
      operationId: search
      parameters:
        - { name: q, in: query, required: true, description: Search term., schema: { type: string } }
        - { name: sort_by_date, in: query, description: 0 = relevance, 1 = date., schema: { type: integer, default: 0 } }
        - { name: type, in: query, description: 'episode, podcast, or curated.', schema: { type: string, enum: [episode, podcast, curated], default: episode } }
        - { name: offset, in: query, description: Offset for pagination., schema: { type: integer, default: 0 } }
        - { name: len_min, in: query, description: Minimum audio length in minutes., schema: { type: integer } }
        - { name: len_max, in: query, description: Maximum audio length in minutes., schema: { type: integer } }
        - { name: episode_count_min, in: query, description: Minimum episode count (podcast search)., schema: { type: integer } }
        - { name: episode_count_max, in: query, description: Maximum episode count (podcast search)., schema: { type: integer } }
        - { name: genre_ids, in: query, description: Comma-separated genre ids to filter by., schema: { type: string } }
        - { name: published_before, in: query, description: Only results published before this timestamp (ms)., schema: { type: integer } }
        - { name: published_after, in: query, description: Only results published after this timestamp (ms)., schema: { type: integer } }
        - { name: only_in, in: query, description: Comma-separated fields to search in (e.g. title,description)., schema: { type: string } }
        - { name: language, in: query, description: Filter by language., schema: { type: string, default: Any language } }
        - { name: region, in: query, description: Filter by country/region., schema: { type: string } }
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
        - { name: unique_podcasts, in: query, description: 1 = at most one episode per podcast., schema: { type: integer, default: 0 } }
        - { name: interviews_only, in: query, description: 1 = only interview episodes., schema: { type: integer, default: 0 } }
        - { name: sponsored_only, in: query, description: 1 = only sponsored content., schema: { type: integer, default: 0 } }
        - { name: page_size, in: query, description: Number of results per page (max 10 by default)., schema: { type: integer, default: 10 } }
      responses:
        '200': { description: Search results. }
  /typeahead:
    get:
      tags: [Search API]
      summary: Typeahead search
      description: Suggest search terms, podcasts, and genres based on a partial query.
      operationId: typeahead
      parameters:
        - { name: q, in: query, required: true, description: Search term., schema: { type: string } }
        - { name: show_podcasts, in: query, description: 1 = include podcast suggestions., schema: { type: integer, default: 0 } }
        - { name: show_genres, in: query, description: 1 = include genre suggestions., schema: { type: integer, default: 0 } }
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Typeahead suggestions. }
  /search_episode_titles:
    get:
      tags: [Search API]
      summary: Search episodes by title
      description: Find individual episodes by searching only their titles.
      operationId: searchEpisodeTitles
      parameters:
        - { name: q, in: query, required: true, description: Search term., schema: { type: string } }
        - { name: podcast_id, in: query, description: Restrict search to a single podcast id., schema: { type: string } }
        - { name: sort_by_date, in: query, description: 0 = relevance, 1 = date., schema: { type: integer, default: 0 } }
        - { name: page_size, in: query, description: Number of results per page., schema: { type: integer, default: 10 } }
      responses:
        '200': { description: Matching episodes. }
  /trending_searches:
    get:
      tags: [Search API]
      summary: Trending search terms
      description: Fetch up-to-date trending search terms on the Listen Notes platform.
      operationId: trendingSearches
      responses:
        '200': { description: Trending search terms. }
  /related_searches:
    get:
      tags: [Search API]
      summary: Related search terms
      description: Fetch up-to-date related search terms for a given search term.
      operationId: relatedSearches
      parameters:
        - { name: q, in: query, required: true, description: Search term., schema: { type: string } }
      responses:
        '200': { description: Related search terms. }
  /spellcheck:
    get:
      tags: [Search API]
      summary: Spell check
      description: Suggest a spell-corrected version of a search term.
      operationId: spellcheck
      parameters:
        - { name: q, in: query, required: true, description: Search term to spell check., schema: { type: string } }
      responses:
        '200': { description: Spell-check suggestions. }
  /best_podcasts:
    get:
      tags: [Directory API]
      summary: Best podcasts by genre
      description: Fetch a curated list of the best podcasts, optionally filtered by genre, region, and language.
      operationId: bestPodcasts
      parameters:
        - { name: genre_id, in: query, description: Genre id (omit or 0 for overall best)., schema: { type: integer } }
        - { name: page, in: query, description: Page number for pagination., schema: { type: integer, default: 1 } }
        - { name: region, in: query, description: Region/country of the chart., schema: { type: string, default: us } }
        - { name: publisher_region, in: query, description: Filter by the publisher's region., schema: { type: string } }
        - { name: language, in: query, description: Filter by podcast language., schema: { type: string } }
        - { name: sort, in: query, description: 'listen_score or recent_added_first.', schema: { type: string, default: listen_score } }
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Best podcasts chart. }
  /podcasts/{id}:
    get:
      tags: [Directory API]
      summary: Get a podcast by id
      description: Fetch detailed metadata and a paginated list of episodes for a podcast by id.
      operationId: getPodcastById
      parameters:
        - { name: id, in: path, required: true, description: Podcast id., schema: { type: string } }
        - { name: next_episode_pub_date, in: query, description: Timestamp (ms) to paginate episodes., schema: { type: integer } }
        - { name: sort, in: query, description: 'recent_first or oldest_first.', schema: { type: string, default: recent_first } }
      responses:
        '200': { description: Podcast metadata and episodes. }
    delete:
      tags: [Podcaster API]
      summary: Request to delete a podcast
      description: Request removal of a podcast from the Listen Notes database.
      operationId: deletePodcastById
      parameters:
        - { name: id, in: path, required: true, description: Podcast id., schema: { type: string } }
        - { name: reason, in: query, description: Reason for the deletion request., schema: { type: string } }
      responses:
        '200': { description: Deletion request accepted. }
  /episodes/{id}:
    get:
      tags: [Directory API]
      summary: Get an episode by id
      description: Fetch detailed metadata for an episode by id.
      operationId: getEpisodeById
      parameters:
        - { name: id, in: path, required: true, description: Episode id., schema: { type: string } }
        - { name: show_transcript, in: query, description: 1 = include transcript when available., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Episode metadata. }
  /episodes:
    post:
      tags: [Directory API]
      summary: Batch fetch episodes
      description: Batch fetch basic metadata for up to 10 episodes by id.
      operationId: batchGetEpisodes
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                ids: { type: string, description: Comma-separated episode ids. }
              required: [ids]
      responses:
        '200': { description: Basic metadata for the requested episodes. }
  /podcasts:
    post:
      tags: [Directory API]
      summary: Batch fetch podcasts
      description: Batch fetch basic metadata for up to 10 podcasts by id.
      operationId: batchGetPodcasts
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                ids: { type: string, description: Comma-separated podcast ids. }
                rsses: { type: string, description: Comma-separated RSS feed URLs. }
                itunes_ids: { type: string, description: Comma-separated iTunes ids. }
                show_latest_episodes: { type: integer, description: 1 = include latest episodes. }
      responses:
        '200': { description: Basic metadata for the requested podcasts. }
  /curated_podcasts:
    get:
      tags: [Directory API]
      summary: Fetch curated lists of podcasts
      description: Fetch a paginated list of curated podcast lists.
      operationId: getCuratedPodcasts
      parameters:
        - { name: page, in: query, description: Page number for pagination., schema: { type: integer, default: 1 } }
      responses:
        '200': { description: Curated lists. }
  /curated_podcasts/{id}:
    get:
      tags: [Directory API]
      summary: Get a curated list by id
      description: Fetch a curated list of podcasts by id, including the podcasts inside it.
      operationId: getCuratedPodcastById
      parameters:
        - { name: id, in: path, required: true, description: Curated list id., schema: { type: string } }
      responses:
        '200': { description: Curated list detail. }
  /genres:
    get:
      tags: [Directory API]
      summary: Fetch podcast genres
      description: Fetch the full list of podcast genres in the Listen Notes taxonomy.
      operationId: getGenres
      parameters:
        - { name: top_level_only, in: query, description: 1 = only top-level genres., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Genre taxonomy. }
  /regions:
    get:
      tags: [Directory API]
      summary: Fetch supported regions
      description: Fetch the list of supported countries/regions for best-podcasts charts.
      operationId: getRegions
      responses:
        '200': { description: Supported regions. }
  /languages:
    get:
      tags: [Directory API]
      summary: Fetch supported languages
      description: Fetch the list of supported languages for podcasts.
      operationId: getLanguages
      responses:
        '200': { description: Supported languages. }
  /just_listen:
    get:
      tags: [Directory API]
      summary: Fetch a random episode
      description: Fetch a random podcast episode (Just Listen) for serendipitous discovery.
      operationId: justListen
      parameters:
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: A random episode. }
  /podcasts/{id}/recommendations:
    get:
      tags: [Directory API]
      summary: Podcast recommendations
      description: Fetch up to eight podcast recommendations for a given podcast.
      operationId: getPodcastRecommendations
      parameters:
        - { name: id, in: path, required: true, description: Podcast id., schema: { type: string } }
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Recommended podcasts. }
  /episodes/{id}/recommendations:
    get:
      tags: [Directory API]
      summary: Episode recommendations
      description: Fetch up to eight episode recommendations for a given episode.
      operationId: getEpisodeRecommendations
      parameters:
        - { name: id, in: path, required: true, description: Episode id., schema: { type: string } }
        - { name: safe_mode, in: query, description: 1 = exclude explicit content., schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Recommended episodes. }
  /playlists:
    get:
      tags: [Playlist API]
      summary: Fetch your playlists
      description: Fetch a paginated list of your Listen Later playlists.
      operationId: getPlaylists
      parameters:
        - { name: sort, in: query, description: 'recent_added_first or recent_updated_first.', schema: { type: string, default: recent_added_first } }
        - { name: page, in: query, description: Page number for pagination., schema: { type: integer, default: 1 } }
      responses:
        '200': { description: Your playlists. }
  /playlists/{id}:
    get:
      tags: [Playlist API]
      summary: Get a playlist by id
      description: Fetch a playlist's info and its items (episodes or podcasts) by id.
      operationId: getPlaylistById
      parameters:
        - { name: id, in: path, required: true, description: Playlist id., schema: { type: string } }
        - { name: type, in: query, description: 'episode_list or podcast_list.', schema: { type: string, default: episode_list } }
        - { name: last_timestamp_ms, in: query, description: Timestamp (ms) to paginate playlist items., schema: { type: integer } }
        - { name: sort, in: query, description: 'recent_added_first or recent_updated_first.', schema: { type: string, default: recent_added_first } }
      responses:
        '200': { description: Playlist info and items. }
  /podcasts/{id}/audience:
    get:
      tags: [Insights API]
      summary: Podcast audience demographics
      description: Fetch audience demographics and insights for a podcast by id.
      operationId: getPodcastAudience
      parameters:
        - { name: id, in: path, required: true, description: Podcast id., schema: { type: string } }
      responses:
        '200': { description: Audience demographics. }
  /podcasts/domains/{domain_name}:
    get:
      tags: [Insights API]
      summary: Podcasts by publisher domain
      description: Fetch podcasts associated with a publisher's domain name.
      operationId: getPodcastsByDomain
      parameters:
        - { name: domain_name, in: path, required: true, description: Publisher domain name (e.g. nytimes.com)., schema: { type: string } }
        - { name: page, in: query, description: Page number for pagination., schema: { type: integer, default: 1 } }
      responses:
        '200': { description: Podcasts for the domain. }
  /podcasts/submit:
    post:
      tags: [Podcaster API]
      summary: Submit a podcast
      description: Submit a podcast to the Listen Notes database by RSS feed URL.
      operationId: submitPodcast
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                rss: { type: string, description: The RSS feed URL of the podcast. }
                email: { type: string, description: Email to notify when the podcast is available. }
              required: [rss]
      responses:
        '200': { description: Submission accepted. }
  /podcasts/{id}/rss:
    post:
      tags: [Podcaster API]
      summary: Refresh a podcast RSS feed
      description: Force a refresh of a podcast's RSS feed to pull in the latest episodes.
      operationId: refreshPodcastRss
      parameters:
        - { name: id, in: path, required: true, description: Podcast id., schema: { type: string } }
      responses:
        '200': { description: Refresh accepted. }
components:
  securitySchemes:
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-ListenAPI-Key
      description: Your Listen API key, sent in the X-ListenAPI-Key request header.