---
title: "Search podcast episode content"
method: GET
path: "/v1/podcasts/episodes/search"
tags: ["Podcast Episode Search", "tier:standard"]
---

# Search podcast episode content

`GET /v1/podcasts/episodes/search`

## Request

- Base URL: `https://api.particle.pro`
- URL: `https://api.particle.pro/v1/podcasts/episodes/search`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

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`.

## Query parameters

- `semantic_search` string: 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.
- `keyword_search` string: 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.
- `keyword_match` 'required' | 'ranked': 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.
- `entity_id` string: Optional entity or person slug or ID. Filters results to episodes featuring this entity. A person with no linked entity matches the episodes they speak in. A slug that names both an entity and a person means the entity; pass the person's ID to filter by the person. For 'every line about X', use /v1/podcasts/mentions instead.
- `entity_type` string: 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.
- `company_id` string: Optional company slug, domain, or ID. Resolves to the company's linked entity and applies as a filter.
- `speaker` string: Optional person slug or ID (a person's entity slug or ID works too). Keeps only segments in which this person speaks a line, and only their lines can be a window's match: 'did X say Y' rather than entity_id's 'Y came up in an episode with X'. With keyword_search, the person's own lines in the segment must carry every quoted phrase, and every unquoted term under keyword_match=required; a phrase may run across their consecutive lines but never into someone else's. Only speaking roles count: a clip of the person played on another show (a soundbite) is not them speaking, so their original turns up and its replays do not. With format=compact the page keeps the same shape and the same filtering, but loads transcripts to apply it. Retrieval narrows to the person's episodes before the line check, so lines of theirs that rank below other segments of those episodes can be missed: an empty page does not prove they never said it. Narrow with podcast_id, episode_id, since or until, or try semantic_search. Cannot be combined with the guest_ filters.
- `episode_id` string: Filter to a specific episode by slug or ID.
- `podcast_id` string: Podcast slug, internal ID, or numeric iTunes ID.
- `type` 'INTRO' | 'PERSONAL_BANTER' | 'TOPIC_DISCUSSION' | 'INTERVIEW' | 'TRANSITION' | 'AD' | 'OUTRO': Segment type filter.
- `role` 'guest' | 'host' | 'panelist' | 'correspondent' | 'speaker' | 'mention': 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.
- `language` string: 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'.
- `since` string: Only segments from episodes published after this date.
- `until` string: Only segments from episodes published on or before this date. A bare date includes that whole day.
- `sort` 'relevance' | 'recency': Sort order. Defaults to relevance.
- `format` 'full' | 'compact': Response shape. 'full' (default) carries each match's bounded dialogue windows and overlapping clips. 'compact' omits windows and clips and skips the transcript load and line scoring that produce them, so the page is a fraction of the size and returns sooner: each match keeps its episode, its segment (id, title, description, summary, bounds) and its relevance score. Use it to screen many results — a fan-out over companies, themes, or dates — and fetch dialogue only for the matches that survive, via GET /v1/podcasts/segments/{id}/transcript or a full-format search narrowed with episode_id.
- `context` integer: 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. Ignored when format=compact.
- `limit` integer: Results per page (1-100, default 25).
- `cursor` string: Opaque cursor from a previous response.
- `guest_occupation` string: Only segments of episodes with a guest listed under this SOC 2018 or ISCO-08 occupation (code, slug, or title), including a SOC group or everyday name such as physicians or doctors. A word with no occupation filters by the field of research or capacity it names: oncologists is field 3211, founders is guest_capacity=executive_founder.
- `guest_field` string: Only segments of episodes with a guest listed under this ANZSRC 2020 field of research (code, slug, or title).
- `guest_standing` 'established' | 'self_described' | 'unverified': Only segments of episodes with a guest whose standing is recognized this way.
- `guest_seniority` 'professional' | 'senior' | 'distinguished': Only segments of episodes with a guest at this seniority or above.
- `guest_capacity` 'researcher' | 'licensed_professional' | 'practitioner' | 'executive_founder' | 'public_official' | 'journalist_analyst' | 'creator_entertainer' | 'athlete_coach' | 'clergy' | 'firsthand' | 'layperson': Only segments of episodes with a guest who knows their field in this capacity, such as executive_founder for founders. It narrows the other filters; an everyday word for a capacity passed as guest_occupation (founders, politicians) lands here too.
- `guest_practicing` boolean: Only segments of episodes with a guest who still works in guest_occupation, a SOC 2018 occupation or group.
- `guest_in_field` boolean: Only segments of episodes with a guest speaking within their field (the guest the other guest_ filters select, when given).

## Response `200`

OK

- PodcastSearchPage
  - `company` CompanyCompact
    - `description` string: Short company description, when known.
    - `domain` string: Primary website domain (e.g. 'nvidia.com'), when known.
    - `id` string, required: Company identifier (domain, slug, or encoded ID)
    - `image_url` string: Company logo or image URL
    - `name` string, required: Company name
    - `slug` string: 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.
    - `ticker` string: Primary stock ticker symbol, when listed.
  - `cursor` string: Opaque cursor; pass back as ?cursor= for the next page
  - `data` PodcastSearchMatch[], nullable, required: Matches on this page, ranked by relevance (default) or recency
    - `clips` ClipInEpisode[], nullable: Highlight clips that overlap this segment, when any exist. Their episode is the match's episode. Omitted when format=compact.
      - `audio_url` string: Direct audio URL for this clip
      - `description` string: AI-generated clip description
      - `duration_seconds` number, double, required: Clip duration
      - `end_seconds` number, double, required: End time within the episode
      - `engagement_score` number, double, required: AI-predicted engagement potential (integer, 0 to 100). Values above 70 are typical for a strong clip.
      - `id` string, required: Unique identifier
      - `intro_statement` string: AI-generated hook text for social sharing
      - `quote` string: Verbatim transcript line from the clip, at most 140 characters, by the clip's speaker where possible
      - `segment` SegmentCompact
        - `id` string, required: Segment ID
        - `title` string, required: Segment title
        - `type` string, required: Segment type
      - `speaker` ClipSpeaker
        - `entity` EntityCompact
          - `company` EntityCompany
            - `domain` string: Company website domain
            - `id` string, required: Company identifier
            - `ticker` string: Primary stock ticker symbol
          - `description` string: Short description
          - `id` string, required: Entity ID
          - `image_url` string: Entity image URL
          - `name` string, required: Entity name
          - `person` EntityPerson
            - `company` string: Current company name
            - `id` string, required: Person identifier
            - `image_url` string: Person headshot URL
            - `title` string: Current role title
          - `slug` string, required: Human-readable slug identifier
          - `type` EntityType
            - `name` string, required: Human-friendly display label (e.g. 'Company').
            - `slug` string, required: Stable identifier, safe to pass to the type query parameter (e.g. 'company').
          - `wikipedia_url` string: Wikipedia URL
        - `name` string, required: Speaker name
        - `person` PersonCompact
          - `description` string: Short description (e.g. current role), when known.
          - `id` string, required: Encoded Person identifier
          - `image_url` string: Canonical headshot URL when one is known for the Person
          - `name` string, required: Display name
          - `slug` string: Stable human-readable handle (e.g. 'satya-nadella'). Recommended canonical identifier on every Particle Pro person surface.
        - `role` string: Speaker role
      - `start_seconds` number, double, required: Start time within the episode
      - `title` string, required: AI-generated clip title
      - `type` 'SPICY' | 'CONTROVERSIAL' | 'EMOTIONAL' | 'FUNNY' | 'SHOCKING' | 'INSIGHTFUL' | 'INFORMATIVE' | 'EDUCATIONAL' | 'PHILOSOPHICAL' | 'AHA_MOMENT' | 'NOTABLE_LINE' | 'BEST_STORY' | 'DEBATE_DISAGREEMENT': Clip type
      - `url` string: Moment link that plays the clip in its episode on Radar: the episode's web_url with ?t= at start_seconds. Cite or share it to link the exact moment. On a clip inside a search match it comes from the match's episode. Omitted when the episode is not known.
    - `episode` EpisodeCompactWithPodcast, required
      - `id` string, required: Episode ID
      - `podcast` PodcastCompact
        - `best_rank` PodcastRankingHandle
          - `captured_at` string, date-time, required
          - `category_slug` string
          - `chart_type` 'top_podcasts', required
          - `country` string
          - `rank` integer, required
          - `source` 'apple' | 'spotify', required
        - `id` string, required: Podcast ID
        - `image_url` string: Cover image URL
        - `popularity` number, double: 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, on endpoints that build this resource from a projection rather than the full podcast row, and in episode stream, feed and archive payloads, which are stored and replayed: read it live from the podcast endpoints.
        - `publisher` PodcastPublisherCompact
          - `id` string, required: Publisher ID
          - `name` string, required: Publisher name
          - `slug` string: 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).
        - `slug` string: Human-readable slug identifier
        - `title` string, required: Podcast title
      - `published_at` string, date-time: Publication date
      - `slug` string: Human-readable slug identifier
      - `title` string, required: Episode title
      - `web_url` string: The episode's page on Radar, where it plays beside its transcript: https://radar.particle.pro/podcasts/{podcast}/episodes/{episode}, each segment the slug or, when there is none, the raw UUID. Append ?t={seconds} to start at a moment; the hit's own url field already does. Omitted for back-catalogue episodes we have not ingested, which have no page, and in episode stream, feed and archive payloads stored before this field shipped (they are replayed as stored): build it from the slugs, or fetch the episode.
    - `match` MatchMetadata, required
      - `relevance_score` number, double: 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.
      - `source` string, required: Which ranking signal produced this result: semantic | keyword | hybrid
    - `segment` SegmentInEpisode, required
      - `audio_url` string: Direct audio URL for this segment
      - `description` string: AI-generated segment description
      - `duration_seconds` number, double, required: Segment duration
      - `end_line` integer: Last transcript line covered by this segment (1-indexed, inclusive). Omitted for episodes segmented before line ranges were recorded.
      - `end_seconds` number, double, required: 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.
      - `id` string, required: Unique identifier
      - `number` integer, required: Segment position within the episode
      - `read_type` string: For AD segments, how the ad was delivered (HOST_READ, PRE_RECORDED, NETWORK_PROMO)
      - `start_line` integer: 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.
      - `start_seconds` number, double, required: Start time within the episode — when the segment's first spoken line begins
      - `summary` string: AI-generated segment summary
      - `title` string, required: AI-generated segment title
      - `type` string, required: Segment type (INTRO, PERSONAL_BANTER, TOPIC_DISCUSSION, INTERVIEW, TRANSITION, AD, OUTRO)
      - `url` string: Moment link that plays the segment on Radar from start_seconds: the episode's web_url with ?t=. Ad placements are segments, so this is also the link to an ad read. On a search match's segment it comes from the match's episode. Omitted only when the segment's episode or its podcast is unavailable.
    - `speakers` EpisodeSpeaker[], nullable: The identified people speaking in the windows' lines, in order of first line, each with their expertise; a line's speaker matches an entry by name. A segment kept by a guest_ filter can also carry lines of other speakers, such as the host, so read each line's speaker here. Omitted when format=compact or when no speaker is identified.
      - `description` string: Brief description of the speaker
      - `descriptor` string: Movie-credits-style role-in-context label for speakers we can describe but not identify by name ("Taylor's Lawyer", "Court Officer"). Co-exists with name carrying the raw STT label when no identity could be established. Rendered by clients when descriptor is non-empty and the speaker is otherwise unresolved.
      - `entity` EntityCompact
        - `company` EntityCompany
          - `domain` string: Company website domain
          - `id` string, required: Company identifier
          - `ticker` string: Primary stock ticker symbol
        - `description` string: Short description
        - `id` string, required: Entity ID
        - `image_url` string: Entity image URL
        - `name` string, required: Entity name
        - `person` EntityPerson
          - `company` string: Current company name
          - `id` string, required: Person identifier
          - `image_url` string: Person headshot URL
          - `title` string: Current role title
        - `slug` string, required: Human-readable slug identifier
        - `type` EntityType
          - `name` string, required: Human-friendly display label (e.g. 'Company').
          - `slug` string, required: Stable identifier, safe to pass to the type query parameter (e.g. 'company').
        - `wikipedia_url` string: Wikipedia URL
      - `expertise` SpeakerExpertise
        - `fields` ExpertiseCode[], nullable: Up to three ANZSRC 2020 fields of research the speaker is listed under, most specific first, none an ancestor of another. Pass a code or slug as guest_field (or field) to filter by it.
          - `code` string, required: The standard's own notation, such as 29-1212 (SOC), 2212 (ISCO), or 320101 (FoR).
          - `group` 'minor' | 'broad' | 'alias': Set for a code that stands for several detailed SOC 2018 occupations: a SOC minor group (such as 29-1000 Healthcare Diagnosing or Treating Practitioners), a broad group (such as 29-1210 Physicians), or an alias, an everyday name such as doctors (physicians and surgeons). Every occupation filter accepts one and matches a speaker listed under any of its occupations.
          - `level` integer: Depth in the standard's official hierarchy: SOC major group 1 and detailed occupation 2; FoR division 1, group 2, field 3; ISCO-08 unit group 4 and minor group 3. ISCO-08 codes are the groups SOC maps to, listed flat without the standard's upper levels. Omitted for a SOC group or alias (see group).
          - `parent_code` string: The standard's official parent code; omitted at the top level and for every ISCO-08 code, since ISCO-08 is listed without its upper levels. A SOC broad group's parent is its minor group and a minor group's its major group, but a detailed SOC occupation's official parent is its major group (29-1211 has parent_code 29-0000), so it can differ from parent, which is the browse parent one level up (29-1210).
          - `slug` string, required: The title as a URL segment, such as cardiologists.
          - `standard` 'soc_2018' | 'isco_08' | 'anzsrc_for_2020', required: The standard the code belongs to: soc_2018 (US Standard Occupational Classification), isco_08 (the ILO's International Standard Classification of Occupations), or anzsrc_for_2020 (ANZSRC Fields of Research).
          - `title` string, required: The standard's official title, such as Cardiologists.
        - `occupations` PersonOccupation[], nullable: Up to three SOC 2018 occupations the speaker is listed under, most specific first, none an ancestor of another. Pass a code or slug as guest_occupation (or occupation) to filter by it.
          - `code` string, required: The standard's own notation, such as 29-1212 (SOC), 2212 (ISCO), or 320101 (FoR).
          - `established` boolean: Whether others conferred the speaker's standing in this occupation, such as a licence or an appointment, rather than the speaker describing it. Present for detailed SOC 2018 occupations only.
          - `group` 'minor' | 'broad' | 'alias': Set for a code that stands for several detailed SOC 2018 occupations: a SOC minor group (such as 29-1000 Healthcare Diagnosing or Treating Practitioners), a broad group (such as 29-1210 Physicians), or an alias, an everyday name such as doctors (physicians and surgeons). Every occupation filter accepts one and matches a speaker listed under any of its occupations.
          - `level` integer: Depth in the standard's official hierarchy: SOC major group 1 and detailed occupation 2; FoR division 1, group 2, field 3; ISCO-08 unit group 4 and minor group 3. ISCO-08 codes are the groups SOC maps to, listed flat without the standard's upper levels. Omitted for a SOC group or alias (see group).
          - `parent_code` string: The standard's official parent code; omitted at the top level and for every ISCO-08 code, since ISCO-08 is listed without its upper levels. A SOC broad group's parent is its minor group and a minor group's its major group, but a detailed SOC occupation's official parent is its major group (29-1211 has parent_code 29-0000), so it can differ from parent, which is the browse parent one level up (29-1210).
          - `practicing` boolean: Whether the speaker still works in this occupation, as opposed to having worked in it. Present for detailed SOC 2018 occupations only.
          - `slug` string, required: The title as a URL segment, such as cardiologists.
          - `standard` 'soc_2018' | 'isco_08' | 'anzsrc_for_2020', required: The standard the code belongs to: soc_2018 (US Standard Occupational Classification), isco_08 (the ILO's International Standard Classification of Occupations), or anzsrc_for_2020 (ANZSRC Fields of Research).
          - `title` string, required: The standard's official title, such as Cardiologists.
        - `seniority` 'professional' | 'senior' | 'distinguished': The highest level the speaker has reached in their field; omitted below professional.
        - `standing` 'established' | 'self_described' | 'unverified', required: How the speaker's standing is recognized: established (conferred by others: a credential, a position, recognition in the field), self_described (claimed by the speaker), or unverified (the records do not say, which never means the speaker is not an expert).
      - `name` string, required: Speaker name
      - `person` PersonCompact
        - `description` string: Short description (e.g. current role), when known.
        - `id` string, required: Encoded Person identifier
        - `image_url` string: Canonical headshot URL when one is known for the Person
        - `name` string, required: Display name
        - `slug` string: Stable human-readable handle (e.g. 'satya-nadella'). Recommended canonical identifier on every Particle Pro person surface.
      - `role` string: Speaker role, always one of HOST, GUEST, PANELIST, CORRESPONDENT, MODERATOR, NARRATOR, ANNOUNCER, VOICE_ACTOR, SOUNDBITE_SPEAKER, AUDIENCE, ADVERTISER, PRODUCER, UNKNOWN, OTHER. Responses carry only HOST, GUEST, PANELIST and CORRESPONDENT unless you widen the set with the role query param.
      - `speaking_duration_seconds` number, double: Total speaking time in seconds
    - `url` string: Moment link that plays the match on Radar: the episode's web_url with ?t= at the first window's start, or at the segment's start when windows are omitted (format=compact). Cite or share it to link the exact moment.
    - `windows` TranscriptWindow[], nullable: Bounded transcript windows highlighting the relevant lines. Omitted when format=compact; otherwise at least one window whenever the segment's transcript is loaded.
      - `end_seconds` number, double, required: Window end time in seconds (episode-absolute)
      - `is_preview` boolean: 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.
      - `lines` TranscriptLine[], nullable, required: Dialogue lines in this window
        - `end_seconds` number, double, required: End time in seconds (episode-absolute)
        - `is_match` boolean: Top-scored line within the window for the current query, on /v1/podcasts/episodes/search results. Not set on /v1/podcasts/mentions.
        - `is_mention` boolean: 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.
        - `matched_terms` string[], nullable: 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.
        - `number` integer, required: Line number within the episode (1-indexed)
        - `role` string: Speaker role (HOST, GUEST, etc.)
        - `segment_id` string: The segment containing this line. Set on is_mention lines of /v1/podcasts/mentions, so a mention can be cited by segment even when its window opened in the previous one (a window starts context_lines before its first mention, and the window's segment is where the window starts). Absent elsewhere.
        - `speaker` string, required: Speaker name or label
        - `start_seconds` number, double, required: Start time in seconds (episode-absolute)
        - `text` string, required: Spoken text
      - `start_seconds` number, double, required: Window start time in seconds (episode-absolute)
      - `url` string: Moment link that plays this window on Radar: the episode's web_url with ?t= at start_seconds.
  - `diagnostics` SearchDiagnostics
    - `filters` SearchFilterReport[], nullable: Every filter the request applied, in the order applied.
      - `emptied_results` boolean: True when removing only this filter makes the search return results.
      - `parameter` string, required: The request parameter this filter came from.
      - `remedy` string: Why this filter excluded everything, and what to change.
      - `retry_with` object: Parameter changes to apply to the same request to recover results. An empty value means remove that parameter.
      - `value` string: The value the request supplied for it.
    - `next_steps` string[], nullable: Concrete retries, most likely to succeed first.
    - `outcome` 'weak_semantic_match' | 'filter_too_narrow' | 'over_constrained' | 'no_match_for_query', required: Stable classification of why the page is empty.
    - `retry_with` object: Parameter changes to apply to the same request to recover results without removing any filter. Set only for weak_semantic_match.
    - `summary` string, required: One-sentence plain statement of what emptied the results.
  - `entity` EntityCompact
    - `company` EntityCompany
      - `domain` string: Company website domain
      - `id` string, required: Company identifier
      - `ticker` string: Primary stock ticker symbol
    - `description` string: Short description
    - `id` string, required: Entity ID
    - `image_url` string: Entity image URL
    - `name` string, required: Entity name
    - `person` EntityPerson
      - `company` string: Current company name
      - `id` string, required: Person identifier
      - `image_url` string: Person headshot URL
      - `title` string: Current role title
    - `slug` string, required: Human-readable slug identifier
    - `type` EntityType
      - `name` string, required: Human-friendly display label (e.g. 'Company').
      - `slug` string, required: Stable identifier, safe to pass to the type query parameter (e.g. 'company').
    - `wikipedia_url` string: Wikipedia URL
  - `has_more` boolean, required: More results available

## Other responses

- `402`: Payment Required. Read error_code. payment_required is the x402 path: either a keyless request being challenged — pay $0.03 in USDC per request (requirements in the PAYMENT-REQUIRED header) or send a pp_ API key — or a supplied payment that failed settlement (details in the PAYMENT-RESPONSE header; retry the same signature before signing a new one). See https://docs.particle.pro/x402. Any other code means the credential was accepted but does not cover this request (a plan or session gate such as premium_required or paid_plan_confirmation_required); its resolve says how to obtain access, and no payment header is sent.
- `default`: Error

---

[API](https://skmtc.dev/particle/apis/particle-api.md) · [All operations](https://skmtc.dev/particle/apis/particle-api/llms.txt) · [OpenAPI document](https://skmtc.dev/particle/apis/particle-api/revisions/416ba82ab9d7?raw)
