Listen Notes Search API

Full-text search across episodes, podcasts, and curated lists by people, places, or topics, with rich filters (genre, language, region, length, publish date, episode count, update frequency). Includes searching individual episodes by title and spell-checking a search term.

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.