> ## Documentation Index
> Fetch the complete documentation index at: https://docs.particle.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Search podcast episode content

> To find podcasts (shows) by name or topic, use `/v1/podcasts/search?q=…`. This endpoint searches *inside* episode dialogue — by meaning (`semantic_search`), by exact phrase (`keyword_search`), or both at once (hybrid). Each result is a segment of an episode, returned with bounded preview windows of dialogue and any highlight clips that overlap the segment.

For "every line about a person or company" use `/v1/podcasts/mentions` instead — that endpoint returns episode-grouped mention windows with line-level highlights and is shaped for the read-everything-about-X use case. `entity_id` and `company_id` here narrow the result set to episodes featuring the resolved entity, but the ranking still comes from `semantic_search` / `keyword_search`.



## OpenAPI

````yaml /openapi.json get /v1/podcasts/episodes/search
openapi: 3.1.0
info:
  description: Public API for Particle — news intelligence, financial data, and analysis.
  title: Particle API
  version: 0.1.0
  x-guidance: >-
    Podcast, people, company and topic intelligence. Authenticate with a pp_ API
    key (X-API-Key header) or pay per request with x402: a keyless call to a
    billable endpoint returns 402 with the payment requirements in the
    PAYMENT-REQUIRED header; sign the USDC transfer and repeat the request with
    PAYMENT-SIGNATURE. Start with GET /v1/podcasts/search?q=<show name>; the
    slugs in responses are the inputs to the other endpoints. Docs:
    https://docs.particle.pro; agent onboarding recipe:
    https://api.particle.pro/auth.md.
servers:
  - url: https://api.particle.pro
security:
  - ApiKeyHeader: []
  - BearerAuth: []
paths:
  /v1/podcasts/episodes/search:
    get:
      tags:
        - Podcast Episode Search
        - tier:standard
      summary: Search podcast episode content
      description: >-
        To find podcasts (shows) by name or topic, use
        `/v1/podcasts/search?q=…`. This endpoint searches *inside* episode
        dialogue — by meaning (`semantic_search`), by exact phrase
        (`keyword_search`), or both at once (hybrid). Each result is a segment
        of an episode, returned with bounded preview windows of dialogue and any
        highlight clips that overlap the segment.


        For "every line about a person or company" use `/v1/podcasts/mentions`
        instead — that endpoint returns episode-grouped mention windows with
        line-level highlights and is shaped for the read-everything-about-X use
        case. `entity_id` and `company_id` here narrow the result set to
        episodes featuring the resolved entity, but the ranking still comes from
        `semantic_search` / `keyword_search`.
      operationId: search-episodes
      parameters:
        - description: >-
            Vector-similarity search by meaning. Express the query the way you'd
            describe the topic to a colleague — paraphrase tolerant, finds
            segments that express the same idea in different vocabulary. Combine
            with keyword_search for hybrid ranking. Describe a topic, not a
            name: to find a specific person or company, filter with entity_id /
            company_id (or use /v1/podcasts/mentions for every line about them)
            — and for an exact token like a ticker, use keyword_search.
          explode: false
          in: query
          name: semantic_search
          schema:
            description: >-
              Vector-similarity search by meaning. Express the query the way
              you'd describe the topic to a colleague — paraphrase tolerant,
              finds segments that express the same idea in different vocabulary.
              Combine with keyword_search for hybrid ranking. Describe a topic,
              not a name: to find a specific person or company, filter with
              entity_id / company_id (or use /v1/podcasts/mentions for every
              line about them) — and for an exact token like a ticker, use
              keyword_search.
            maxLength: 500
            type: string
        - description: >-
            BM25 lexical search over dialogue. Use when an exact token must
            appear verbatim — tickers, drug names, product codes. By default
            every token must appear somewhere in the matched segment (see
            keyword_match). Wrap any token sequence in double quotes (e.g.
            "machine learning") to additionally require those words adjacent and
            in order in the segment's spoken dialogue — a speaker's own name is
            not indexed as dialogue, so quoting a person's name finds segments
            where the name appears in what was said, not segments they speak in.
            Adjacency spans consecutive lines, so a phrase may rarely straddle a
            line break. Multiple quoted phrases AND together (e.g. "central
            bank" "interest rates"). There is no boolean OR — a bare OR is
            treated as an ordinary word, so pass alternatives as separate
            requests.
          explode: false
          in: query
          name: keyword_search
          schema:
            description: >-
              BM25 lexical search over dialogue. Use when an exact token must
              appear verbatim — tickers, drug names, product codes. By default
              every token must appear somewhere in the matched segment (see
              keyword_match). Wrap any token sequence in double quotes (e.g.
              "machine learning") to additionally require those words adjacent
              and in order in the segment's spoken dialogue — a speaker's own
              name is not indexed as dialogue, so quoting a person's name finds
              segments where the name appears in what was said, not segments
              they speak in. Adjacency spans consecutive lines, so a phrase may
              rarely straddle a line break. Multiple quoted phrases AND together
              (e.g. "central bank" "interest rates"). There is no boolean OR — a
              bare OR is treated as an ordinary word, so pass alternatives as
              separate requests.
            maxLength: 500
            type: string
        - description: >-
            How unquoted keyword_search terms are applied. 'required' (default)
            filters to segments containing every term, so results are guaranteed
            to contain what you typed — this also constrains semantic_search,
            making a hybrid query an intersection of the two. 'ranked' instead
            lets unquoted terms only boost BM25 relevance without excluding
            anything, which widens recall for loose bag-of-words queries but
            returns segments that may contain none of them. Quoted phrases are
            unaffected: they filter in BOTH modes, so to relax a phrase remove
            its quotes. Ignored when keyword_search is empty.
          explode: false
          in: query
          name: keyword_match
          schema:
            default: required
            description: >-
              How unquoted keyword_search terms are applied. 'required'
              (default) filters to segments containing every term, so results
              are guaranteed to contain what you typed — this also constrains
              semantic_search, making a hybrid query an intersection of the two.
              'ranked' instead lets unquoted terms only boost BM25 relevance
              without excluding anything, which widens recall for loose
              bag-of-words queries but returns segments that may contain none of
              them. Quoted phrases are unaffected: they filter in BOTH modes, so
              to relax a phrase remove its quotes. Ignored when keyword_search
              is empty.
            enum:
              - required
              - ranked
            type: string
        - description: >-
            Optional entity slug or ID. Filters results to episodes featuring
            this entity. For 'every line about X', use /v1/podcasts/mentions
            instead.
          explode: false
          in: query
          name: entity_id
          schema:
            description: >-
              Optional entity slug or ID. Filters results to episodes featuring
              this entity. For 'every line about X', use /v1/podcasts/mentions
              instead.
            type: string
        - description: >-
            Optional entity category slug. Filters to episodes that *mention*
            any entity in that category (e.g. 'company', 'school', 'book').
            Speakers are always people, so this filter only narrows mentioned
            entities. Cannot be combined with 'role'. Ignored when entity_id
            resolves to a specific entity. See GET /v1/entities/types for the
            available slugs.
          explode: false
          in: query
          name: entity_type
          schema:
            description: >-
              Optional entity category slug. Filters to episodes that *mention*
              any entity in that category (e.g. 'company', 'school', 'book').
              Speakers are always people, so this filter only narrows mentioned
              entities. Cannot be combined with 'role'. Ignored when entity_id
              resolves to a specific entity. See GET /v1/entities/types for the
              available slugs.
            type: string
        - description: >-
            Optional company slug, domain, or ID. Resolves to the company's
            linked entity and applies as a filter.
          explode: false
          in: query
          name: company_id
          schema:
            description: >-
              Optional company slug, domain, or ID. Resolves to the company's
              linked entity and applies as a filter.
            type: string
        - description: Filter to a specific episode by slug or ID.
          explode: false
          in: query
          name: episode_id
          schema:
            description: Filter to a specific episode by slug or ID.
            type: string
        - description: Podcast slug, internal ID, or numeric iTunes ID.
          explode: false
          in: query
          name: podcast_id
          schema:
            description: Podcast slug, internal ID, or numeric iTunes ID.
            type: string
        - description: Segment type filter.
          explode: false
          in: query
          name: type
          schema:
            description: Segment type filter.
            enum:
              - INTRO
              - PERSONAL_BANTER
              - TOPIC_DISCUSSION
              - INTERVIEW
              - TRANSITION
              - AD
              - OUTRO
            type: string
        - description: >-
            How the entity must relate to the episode. Speaking roles: 'guest',
            'host', 'panelist', 'correspondent', or 'speaker' for any of them.
            'mention' means the entity is talked about rather than speaking.
            Omit to match both. Matches the role values on
            /v1/podcasts/episodes.
          explode: false
          in: query
          name: role
          schema:
            description: >-
              How the entity must relate to the episode. Speaking roles:
              'guest', 'host', 'panelist', 'correspondent', or 'speaker' for any
              of them. 'mention' means the entity is talked about rather than
              speaking. Omit to match both. Matches the role values on
              /v1/podcasts/episodes.
            enum:
              - guest
              - host
              - panelist
              - correspondent
              - speaker
              - mention
            type: string
        - description: >-
            Restrict to episodes of podcasts in this language (ISO 639-1 code,
            e.g. 'fr'). Matches the podcast's primary language subtag, so 'fr'
            covers 'fr-FR'.
          explode: false
          in: query
          name: language
          schema:
            description: >-
              Restrict to episodes of podcasts in this language (ISO 639-1 code,
              e.g. 'fr'). Matches the podcast's primary language subtag, so 'fr'
              covers 'fr-FR'.
            examples:
              - fr
            type: string
        - description: Only segments from episodes published after this date.
          explode: false
          in: query
          name: since
          schema:
            description: Only segments from episodes published after this date.
            examples:
              - '2024-01-01'
            type: string
        - description: >-
            Only segments from episodes published on or before this date. A bare
            date includes that whole day.
          explode: false
          in: query
          name: until
          schema:
            description: >-
              Only segments from episodes published on or before this date. A
              bare date includes that whole day.
            examples:
              - '2024-06-01'
            type: string
        - description: Sort order. Defaults to relevance.
          explode: false
          in: query
          name: sort
          schema:
            description: Sort order. Defaults to relevance.
            enum:
              - relevance
              - recency
            type: string
        - description: >-
            Lines of surrounding dialogue around each matched line (1-15,
            default 1). Widens each match's transcript window in place — request
            more context instead of fetching the full transcript. Window size
            stays bounded even at the maximum.
          explode: false
          in: query
          name: context
          schema:
            default: 1
            description: >-
              Lines of surrounding dialogue around each matched line (1-15,
              default 1). Widens each match's transcript window in place —
              request more context instead of fetching the full transcript.
              Window size stays bounded even at the maximum.
            format: int64
            maximum: 15
            minimum: 1
            type: integer
        - description: Results per page (1-100, default 25).
          explode: false
          in: query
          name: limit
          schema:
            default: 25
            description: Results per page (1-100, default 25).
            format: int64
            maximum: 100
            minimum: 1
            type: integer
        - description: Opaque cursor from a previous response.
          explode: false
          in: query
          name: cursor
          schema:
            description: Opaque cursor from a previous response.
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PodcastSearchPage'
          description: OK
        default:
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/PlatformError'
          description: Error
      x-codeSamples:
        - label: cURL
          lang: curl
          source: |-
            curl -H "X-API-Key: $PARTICLE_API_KEY" \
              "https://api.particle.pro/v1/podcasts/episodes/search?keyword_match=required&context=1&limit=25"
components:
  schemas:
    PodcastSearchPage:
      additionalProperties: false
      properties:
        company:
          $ref: '#/components/schemas/CompanyCompact'
          description: >-
            Resolved company, when company_id filtered the result set. Omitted
            when only entity_id was provided.
        cursor:
          description: Opaque cursor; pass back as ?cursor= for the next page
          type: string
        data:
          description: Matches on this page, ranked by relevance (default) or recency
          items:
            $ref: '#/components/schemas/PodcastSearchMatch'
          type:
            - array
            - 'null'
        diagnostics:
          $ref: '#/components/schemas/SearchDiagnostics'
          description: >-
            Present only when data is empty: which filter excluded everything,
            why, and the parameter change to retry with.
        entity:
          $ref: '#/components/schemas/EntityCompact'
          description: >-
            Resolved entity, when entity_id or company_id filtered the result
            set
        has_more:
          description: More results available
          type: boolean
      required:
        - data
        - has_more
      type: object
    PlatformError:
      additionalProperties: false
      properties:
        detail:
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          examples:
            - Property foo is required but is missing.
          type: string
        error_code:
          type: string
        errors:
          description: Optional list of individual error details
          items:
            $ref: '#/components/schemas/ErrorDetail'
          type:
            - array
            - 'null'
        instance:
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          examples:
            - https://example.com/error-log/abc123
          format: uri
          type: string
        resolve:
          $ref: '#/components/schemas/ErrorResolve'
        status:
          description: HTTP status code
          examples:
            - 400
          format: int64
          type: integer
        title:
          description: >-
            A short, human-readable summary of the problem type. This value
            should not change between occurrences of the error.
          examples:
            - Bad Request
          type: string
        type:
          default: about:blank
          description: A URI reference to human-readable documentation for the error.
          examples:
            - https://example.com/errors/example
          format: uri
          type: string
      type: object
    CompanyCompact:
      additionalProperties: false
      properties:
        description:
          description: Short company description, when known.
          type: string
        domain:
          description: Primary website domain (e.g. 'nvidia.com'), when known.
          type: string
        id:
          description: Company identifier (domain, slug, or encoded ID)
          type: string
        image_mode:
          description: >-
            Image presentation policy. AUTOMATIC permits client fallbacks,
            CUSTOM requires image_url, and NONE suppresses all image fallbacks.
          enum:
            - AUTOMATIC
            - CUSTOM
            - NONE
          type: string
        image_url:
          description: Company logo or image URL
          type: string
        name:
          description: Company name
          type: string
        slug:
          description: >-
            Stable human-readable handle (the linked knowledge-graph slug, e.g.
            'nvidia'), when known. Companies have no slug of their own; prefer
            this for display and pass it (or id) to /v1/companies.
          type: string
        ticker:
          description: Primary stock ticker symbol, when listed.
          type: string
      required:
        - id
        - name
      type: object
    PodcastSearchMatch:
      additionalProperties: false
      properties:
        clips:
          description: Highlight clips that overlap this segment, when any exist
          items:
            $ref: '#/components/schemas/Clip'
          type:
            - array
            - 'null'
        episode:
          $ref: '#/components/schemas/EpisodeCompactWithPodcast'
          description: Episode containing the match
        match:
          $ref: '#/components/schemas/MatchMetadata'
          description: Source and relevance metadata
        segment:
          $ref: '#/components/schemas/Segment'
          description: Matching segment
        windows:
          description: >-
            Bounded transcript windows highlighting the relevant lines. Always
            at least one window when the segment's transcript is loaded.
          items:
            $ref: '#/components/schemas/TranscriptWindow'
          type:
            - array
            - 'null'
      required:
        - episode
        - segment
        - windows
        - match
      type: object
    SearchDiagnostics:
      additionalProperties: false
      properties:
        filters:
          description: Every filter the request applied, in the order applied.
          items:
            $ref: '#/components/schemas/SearchFilterReport'
          type:
            - array
            - 'null'
        next_steps:
          description: Concrete retries, most likely to succeed first.
          items:
            type: string
          type:
            - array
            - 'null'
        outcome:
          description: Stable classification of why the page is empty.
          enum:
            - filter_too_narrow
            - over_constrained
            - no_match_for_query
          type: string
        summary:
          description: One-sentence plain statement of what emptied the results.
          type: string
      required:
        - outcome
        - summary
      type: object
    EntityCompact:
      additionalProperties: false
      properties:
        company:
          $ref: '#/components/schemas/EntityCompany'
          description: Linked company record, if this entity is a known company
        description:
          description: Short description
          type: string
        id:
          description: Entity ID
          type: string
        image_url:
          description: Entity image URL
          type: string
        name:
          description: Entity name
          type: string
        person:
          $ref: '#/components/schemas/EntityPerson'
          description: Linked person record, if this entity is a known person
        slug:
          description: Human-readable slug identifier
          type: string
        type:
          $ref: '#/components/schemas/EntityType'
          description: Category. Omitted when the entity falls outside the supported set.
        wikipedia_url:
          description: Wikipedia URL
          type: string
      required:
        - id
        - slug
        - name
      type: object
    ErrorDetail:
      additionalProperties: false
      properties:
        location:
          description: >-
            Where the error occurred, e.g. 'body.items[3].tags' or
            'path.thing-id'
          type: string
        message:
          description: Error message text
          type: string
        value:
          description: The value at the given location
      type: object
    ErrorResolve:
      additionalProperties: false
      properties:
        action:
          type: string
        endpoint:
          type: string
        message:
          type: string
        method:
          type: string
        url:
          type: string
      required:
        - message
      type: object
    Clip:
      additionalProperties: false
      properties:
        audio_url:
          description: Direct audio URL for this clip
          type: string
        description:
          description: AI-generated clip description
          type: string
        duration_seconds:
          description: Clip duration
          format: double
          type: number
        end_seconds:
          description: End time within the episode
          format: double
          type: number
        engagement_score:
          description: >-
            AI-predicted engagement potential (integer, 0 to 100). Values above
            70 are typical for a strong clip.
          format: double
          type: number
        episode:
          $ref: '#/components/schemas/EpisodeCompactWithPodcast'
          description: Parent episode with podcast context
        id:
          description: Unique identifier
          type: string
        intro_statement:
          description: AI-generated hook text for social sharing
          type: string
        segment:
          $ref: '#/components/schemas/SegmentCompact'
          description: Parent segment context
        speaker:
          $ref: '#/components/schemas/ClipSpeaker'
          description: Primary speaker in this clip
        start_seconds:
          description: Start time within the episode
          format: double
          type: number
        title:
          description: AI-generated clip title
          type: string
        type:
          description: Clip type
          enum:
            - SPICY
            - CONTROVERSIAL
            - EMOTIONAL
            - FUNNY
            - SHOCKING
            - INSIGHTFUL
            - INFORMATIVE
            - EDUCATIONAL
            - PHILOSOPHICAL
            - AHA_MOMENT
            - NOTABLE_LINE
            - BEST_STORY
            - DEBATE_DISAGREEMENT
          type: string
      required:
        - id
        - title
        - engagement_score
        - start_seconds
        - end_seconds
        - duration_seconds
      type: object
    EpisodeCompactWithPodcast:
      additionalProperties: false
      properties:
        id:
          description: Episode ID
          type: string
        podcast:
          $ref: '#/components/schemas/PodcastCompact'
          description: Parent podcast
        published_at:
          description: Publication date
          format: date-time
          type: string
        slug:
          description: Human-readable slug identifier
          type: string
        title:
          description: Episode title
          type: string
      required:
        - id
        - title
      type: object
    MatchMetadata:
      additionalProperties: false
      properties:
        relevance_score:
          description: >-
            Raw relevance score from the underlying ranker. For semantic this is
            cosine similarity in [-1, 1] (typically 0..1). For keyword this is
            the BM25 score (unbounded, higher = better). For hybrid this is the
            reciprocal-rank-fusion score (small positive number, higher =
            better). Compare scores within a single response, not across
            queries.
          format: double
          type: number
        source:
          description: >-
            Which ranking signal produced this result: semantic | keyword |
            hybrid
          type: string
      required:
        - source
      type: object
    Segment:
      additionalProperties: false
      properties:
        audio_url:
          description: Direct audio URL for this segment
          type: string
        description:
          description: AI-generated segment description
          type: string
        duration_seconds:
          description: Segment duration
          format: double
          type: number
        end_line:
          description: >-
            Last transcript line covered by this segment (1-indexed, inclusive).
            Omitted for episodes segmented before line ranges were recorded.
          format: int64
          type: integer
        end_seconds:
          description: >-
            End time within the episode — when the segment's last spoken line
            ends. Where start_line/end_line are present, segments partition the
            transcript's lines rather than tiling the wall-clock timeline, and
            the interval between this and the next segment's start_seconds
            contains no transcribed speech (typically under a second,
            occasionally minutes of music or silence). Segments without a
            recorded line range were produced by an earlier segmenter and a
            small share of them do leave transcript lines uncovered, so a gap
            between two such segments may contain real speech. Use
            start_line/end_line to slice a transcript losslessly.
          format: double
          type: number
        episode:
          $ref: '#/components/schemas/EpisodeCompactWithPodcast'
          description: Parent episode with podcast context
        id:
          description: Unique identifier
          type: string
        number:
          description: Segment position within the episode
          format: int64
          type: integer
        read_type:
          description: >-
            For AD segments, how the ad was delivered (HOST_READ, PRE_RECORDED,
            NETWORK_PROMO)
          type: string
        start_line:
          description: >-
            First transcript line covered by this segment (1-indexed,
            inclusive). Line numbers match the number field of GET
            /v1/podcasts/episodes/{id}/transcript lines. This segment's end_line
            + 1 is the next segment's start_line, and the segments together
            cover every line of the transcript. Omitted for episodes segmented
            before line ranges were recorded.
          format: int64
          type: integer
        start_seconds:
          description: >-
            Start time within the episode — when the segment's first spoken line
            begins
          format: double
          type: number
        summary:
          description: AI-generated segment summary
          type: string
        title:
          description: AI-generated segment title
          type: string
        type:
          description: >-
            Segment type (INTRO, PERSONAL_BANTER, TOPIC_DISCUSSION, INTERVIEW,
            TRANSITION, AD, OUTRO)
          type: string
      required:
        - id
        - number
        - type
        - title
        - start_seconds
        - end_seconds
        - duration_seconds
      type: object
    TranscriptWindow:
      additionalProperties: false
      properties:
        end_seconds:
          description: Window end time in seconds (episode-absolute)
          format: double
          type: number
        is_preview:
          description: >-
            True when the window is the segment's leading lines (a fallback for
            when line-level scoring couldn't pinpoint any line) rather than
            scored matches. False or absent on a scored window.
          type: boolean
        lines:
          description: Dialogue lines in this window
          items:
            $ref: '#/components/schemas/TranscriptLine'
          type:
            - array
            - 'null'
        start_seconds:
          description: Window start time in seconds (episode-absolute)
          format: double
          type: number
      required:
        - start_seconds
        - end_seconds
        - lines
      type: object
    SearchFilterReport:
      additionalProperties: false
      properties:
        emptied_results:
          description: True when removing only this filter makes the search return results.
          type: boolean
        parameter:
          description: The request parameter this filter came from.
          type: string
        remedy:
          description: Why this filter excluded everything, and what to change.
          type: string
        retry_with:
          additionalProperties:
            type: string
          description: >-
            Parameter changes to apply to the same request to recover results.
            An empty value means remove that parameter.
          type: object
        value:
          description: The value the request supplied for it.
          type: string
      required:
        - parameter
      type: object
    EntityCompany:
      additionalProperties: false
      properties:
        domain:
          description: Company website domain
          type: string
        id:
          description: Company identifier
          type: string
        ticker:
          description: Primary stock ticker symbol
          type: string
      required:
        - id
      type: object
    EntityPerson:
      additionalProperties: false
      properties:
        company:
          description: Current company name
          type: string
        id:
          description: Person identifier
          type: string
        image_url:
          description: Person headshot URL
          type: string
        title:
          description: Current role title
          type: string
      required:
        - id
      type: object
    EntityType:
      additionalProperties: false
      properties:
        name:
          description: Human-friendly display label (e.g. 'Company').
          type: string
        slug:
          description: >-
            Stable identifier, safe to pass to the type query parameter (e.g.
            'company').
          type: string
      required:
        - slug
        - name
      type: object
    SegmentCompact:
      additionalProperties: false
      properties:
        id:
          description: Segment ID
          type: string
        title:
          description: Segment title
          type: string
        type:
          description: Segment type
          type: string
      required:
        - id
        - type
        - title
      type: object
    ClipSpeaker:
      additionalProperties: false
      properties:
        entity:
          $ref: '#/components/schemas/EntityCompact'
          description: Linked knowledge graph entity, when this speaker is identified
        name:
          description: Speaker name
          type: string
        person:
          $ref: '#/components/schemas/PersonCompact'
          description: Linked first-class Person, when the speaker has been resolved
        role:
          description: Speaker role
          type: string
      required:
        - name
      type: object
    PodcastCompact:
      additionalProperties: false
      properties:
        best_rank:
          $ref: '#/components/schemas/PodcastRankingHandle'
          description: >-
            The single best (lowest-numbered) chart position this podcast
            currently holds across all charts. Omitted when the podcast holds no
            current chart appearances, and on endpoints that do not attach it.
            Reading a full chart (with country/category/source filters and
            history) remains premium; a single show's own placement is available
            on every plan.
        id:
          description: Podcast ID
          type: string
        image_url:
          description: Cover image URL
          type: string
        popularity:
          description: >-
            Global popularity percentile in (0,1], a cume_dist ranking over all
            currently-charting podcasts (Apple Podcasts charts). Higher is more
            popular. Omitted when the podcast is not currently charting, and on
            endpoints that build this resource from a projection rather than the
            full podcast row.
          format: double
          type: number
        publisher:
          $ref: '#/components/schemas/PodcastPublisherCompact'
          description: >-
            Publisher (network) attributed to this podcast. Present only when
            the embedding endpoint preloads publisher attribution and the
            podcast's publisher is known.
        slug:
          description: Human-readable slug identifier
          type: string
        title:
          description: Podcast title
          type: string
      required:
        - id
        - title
      type: object
    TranscriptLine:
      additionalProperties: false
      properties:
        end_seconds:
          description: End time in seconds (episode-absolute)
          format: double
          type: number
        is_match:
          description: >-
            Top-scored line within the window for the current query, on
            /v1/podcasts/episodes/search results. Not set on
            /v1/podcasts/mentions.
          type: boolean
        is_mention:
          description: >-
            Line contains a textual mention of the resolved entity. Set on
            /v1/podcasts/mentions only — /v1/podcasts/episodes/search treats
            entity_id as a filter and does not mark mention lines.
          type: boolean
        matched_terms:
          description: >-
            Terms from the query that occur in this line, longest-first, for
            clients to highlight. Locate them case-insensitively: each term is
            spelled as the query spelled it, which may differ in case from the
            line's text (query "openai" is reported for a line reading
            "OpenAI"). Whole-token matches only — a term never matches inside a
            longer word, so "AI" is not reported for "said". A multi-word query
            yields the whole phrase ("founder mode") when it occurs
            contiguously, so clients mark it as one span rather than
            highlighting each word separately; individual words appear only
            where they occur outside the phrase. Only the longest term is
            reported at any position, so terms never overlap. On
            /v1/podcasts/episodes/search this is set on any line in the window
            containing the query, not only is_match lines; on
            /v1/podcasts/mentions it is set only on is_mention lines. Absent
            when nothing matched or the query was not text-based.
          items:
            type: string
          type:
            - array
            - 'null'
        number:
          description: Line number within the episode (1-indexed)
          format: int64
          type: integer
        role:
          description: Speaker role (HOST, GUEST, etc.)
          type: string
        speaker:
          description: Speaker name or label
          type: string
        start_seconds:
          description: Start time in seconds (episode-absolute)
          format: double
          type: number
        text:
          description: Spoken text
          type: string
      required:
        - number
        - speaker
        - start_seconds
        - end_seconds
        - text
      type: object
    PersonCompact:
      additionalProperties: false
      properties:
        description:
          description: Short description (e.g. current role), when known.
          type: string
        id:
          description: Encoded Person identifier
          type: string
        image_url:
          description: Canonical headshot URL when one is known for the Person
          type: string
        name:
          description: Display name
          type: string
        slug:
          description: >-
            Stable human-readable handle (e.g. 'satya-nadella'). Recommended
            canonical identifier on every Particle Pro person surface.
          type: string
      required:
        - id
        - name
      type: object
    PodcastRankingHandle:
      additionalProperties: false
      properties:
        captured_at:
          format: date-time
          type: string
        category_slug:
          type: string
        chart_type:
          enum:
            - top_podcasts
          type: string
        country:
          type: string
        rank:
          format: int64
          type: integer
        source:
          enum:
            - apple
            - spotify
          type: string
      required:
        - source
        - chart_type
        - rank
        - captured_at
      type: object
    PodcastPublisherCompact:
      additionalProperties: false
      properties:
        id:
          description: Publisher ID
          type: string
        name:
          description: Publisher name
          type: string
        slug:
          description: >-
            Human-readable slug identifier (e.g., 'goalhanger',
            'iheartpodcasts'). When present, accepted in place of the ID
            anywhere a publisher reference is taken in the API. Occasionally
            absent on publishers whose name doesn't slugify (e.g., scripts not
            representable in ASCII URL slugs).
          type: string
      required:
        - id
        - name
      type: object
  securitySchemes:
    ApiKeyHeader:
      description: Pass your API key in the X-API-Key header (recommended).
      in: header
      name: X-API-Key
      type: apiKey
    BearerAuth:
      description: Pass your API key as a Bearer token in the Authorization header.
      scheme: bearer
      type: http

````