Skip to main content
The API grows additively — new fields, parameters, and endpoints never break an existing call. Breaking changes are rare, announced ahead of time, and called out here explicitly.

September 2026

Pay per request with x402 — keyless access for agents

Every standard and premium /v1/* endpoint now accepts an x402 USDC micropayment in place of an API key. A keyless request returns 402 with the payment requirements in a PAYMENT-REQUIRED header and a payment_required body; the agent signs the transfer, retries with PAYMENT-SIGNATURE, and receives the response plus a PAYMENT-RESPONSE receipt. Prices are one cent per unit of cost weight (0.01standard,upto0.01 standard, up to 0.03 premium); failed requests are never charged. Nothing changes for keyed traffic: any presented credential — even an invalid one — takes the normal authentication path. Free endpoints stay free, and alerts and enterprise surfaces still require an account.

Buy-side recommendations for advertisers

GET /v1/companies/{id}/podcast/recommendations (premium) lists the shows a company could advertise on next: every show it has never bought, ranked by relatedness to the shows its sponsors already run ads on, each weighted by how much it advertises there. include=via attaches the company’s own shows behind each pick; min_score and language filter. In the temporal holdout it recovered advertisers’ later buys at 13× the rate of category-by-popularity. MCP: include: ["podcast_recommendations"] on particle_company_get. GET /v1/podcasts/{id}/recommendations/sponsors gains include=contacts — up to three people at each recommended sponsor’s company most likely to own a sponsorship decision (marketing, partnerships, brand, media and advertising, communications, growth, then other executives), each with a title, a role class and a LinkedIn URL when known — and exclude_top_advertisers=N, which drops the N most active advertisers corpus-wide so the list shows the long tail where it is strongest. GET /v1/companies/{id}/people gains role= with the same classes (plus other), matching the classifier’s first-match rule. GET /v1/podcasts/{id}/related and particle_podcast_list_related gain catalogue filters: language, publishing_status, suitability_tier, min_popularity and exclude_same_publisher, applied to the stored ranking with pagination over the filtered list.

GET /v1/podcasts/episodes/lookup — resolve a hosting platform’s episode ID

platform=megaphone, omny, acast and art19 resolve a podcast host’s own episode ID. The ID is read from the episode’s audio URL, so coverage is simply whether that episode is served by that host, and an episode resolves under exactly one of them. Pass the bare ID rather than the audio URL: publishers route audio through arbitrary stacks of tracking prefixes, so the URL you hold may not resemble the one we stored, but the ID inside it is stable.

GET /v1/podcasts/episodes/lookup — resolve an RSS guid or PodcastIndex episode ID

platform=guid resolves the <guid> an episode carries in its publisher’s feed — the podcast ecosystem’s canonical episode identifier, and the broadest coverage of any identifier on this endpoint at roughly 89% of episodes. Guids are matched exactly as supplied and never parsed, since publishers use everything from UUIDs to permalink URLs. A guid identifies an episode within its feed rather than globally, so for the ~1.4% that reach more than one episode the lookup returns the one on the most popular podcast, deterministically. platform=podcastindex resolves a PodcastIndex episode ID. These are numeric and unique, so no tie-breaking applies; a non-numeric value is reported as a miss rather than failing the whole request.

GET /v1/podcasts/{id}/related — shows like this show, with the reasons

A new standard-tier GET /v1/podcasts/{id}/related returns the shows most related to a podcast, best first. Each result carries a calibrated score in (0, 1], a coarse bandstrong (same beat and audience), moderate (overlapping subject or audience), weak (a loose connection) — and, with include=basis, a basis object naming the signals behind the pairing: content_similarity of recent episodes, topic_overlap with the top shared_topics, shared_guest_count with named shared_guests, same_publisher, shared_sponsor_count, and shared_category_count. Branch on band; the score’s exact thresholds may be recalibrated as the ranker improves. Related sets are precomputed per show from its embedded transcripts, topic profile, guest roster, network, and advertisers, restricted to the show’s language, and refreshed as new episodes land, so the endpoint is a fast page read. A show whose set has not been computed yet returns 200 with an empty data array, not 404. GET /v1/podcasts/{id} gains include=related for the five most related shows inline in lean form. The ranker was validated against Apple’s “You Might Also Like” lists, a temporal shared-guest holdout, and a calibrated editorial judge; the measured recall and precision figures are published alongside the methodology once the full-catalogue evaluation completes.

GET /v1/podcasts/episodes/{id}/related — episodes elsewhere covering the same story or subject

A new standard-tier GET /v1/podcasts/episodes/{id}/related returns episodes from other shows that cover the same story or subject as an episode, best first. Each result carries a score, a band, and with include=basis the reasons: content similarity, shared entities, shared topics, a shared news story, shared guests, and days apart. published_within_days narrows to a recency window (news-style use) and same_podcast=true opts the show’s own episodes in. Results are computed live from the episode’s content centroid and reranked on the structured signals, then cached, so first calls are slower than repeats. MCP: particle_podcast_list_related_episodes.

GET /v1/podcasts/{id}/recommendations/sponsors — advertisers that buy shows like this one

A new premium-tier GET /v1/podcasts/{id}/recommendations/sponsors is the prospecting list for a show selling its own inventory: sponsors that run on the podcast’s related shows but not on this one, ranked by how related those venues are, how much the sponsor buys there, and how recently. Each row carries the sponsor with its linked company (the path to people to contact), a score and band, shared_show_count, total_ads, last_ad_at, and with include=via the related shows that run it. active_since keeps only sponsors still buying after a date. The podcast detail embeds the first five with include=recommended_sponsors. MCP: include: ["recommended_sponsors"] on particle_podcast_resolve.

GET /v1/podcasts/guests/{id}/recommendations/podcasts and GET /v1/podcasts/{id}/recommendations/guests — the pitch list and the booking pipeline

Two standard-tier views derived from related sets and guest rosters. GET /v1/podcasts/guests/{id}/recommendations/podcasts lists shows a person has not appeared on, ranked by relatedness to the shows they have, with include=via naming the person’s own shows behind each recommendation. GET /v1/podcasts/{id}/recommendations/guests lists people who have guested on the show’s related shows but never on this one, with circuit regulars excluded and include=via naming the venues. Both return 200 with an empty data array until the relevant related sets have been computed. The podcast detail embeds the first five recommended guests with include=recommended_guests.

GET /v1/podcasts/episodes/lookup — resolve a YouTube video ID

platform=youtube now resolves a YouTube video to the episode it belongs to, alongside the existing apple / itunes support. Pass a bare video ID or a full URL — watch?v=, youtu.be/, /live/, /shorts/ and /embed/ forms are all accepted. Coverage reflects the videos we have already discovered for an episode (feed links, Podcasting 2.0 alternate enclosures, Media RSS, show-note URLs, channel matching) rather than a per-episode lookup against YouTube, so every video we hold resolves — there is no partial-window caveat like Apple’s. Where one video is attached to several episodes, the lookup returns the episode whose video came from the most precise discovery method — a feed enclosure or a runtime-validated channel match ahead of a URL scraped from show notes — with podcast popularity breaking ties, so repeated calls agree.

August 2026

GET /v1/podcasts/episodes/lookup — resolve an Apple Podcasts episode ID

A new standard-tier GET /v1/podcasts/episodes/lookup turns an Apple Podcasts episode identifier — the ?i= value in an Apple Podcasts URL — into a Particle episode. It is the episode-level counterpart to GET /v1/podcasts/lookup and takes the same shape: one platform, up to 100 identifiers, one echoed result per input, with the episode key omitted for identifiers that don’t resolve. Each hit carries the parent podcast, so one call tells you both the episode and its show. A full Apple Podcasts episode URL is accepted in place of a bare ID. Coverage is partial by design: Apple only publishes episode IDs through a show’s catalog listing, which is capped at that show’s 200 most recent episodes, so deep back-catalog episodes have no Apple ID to match. Recent episodes and small-to-mid shows resolve almost always. Treat a miss as a normal outcome and fall back to GET /v1/podcasts/episodes/search.

GET /v1/podcasts/advertising/leaderboard/preview — the leaderboard’s open teaser

A new standard-tier GET /v1/podcasts/advertising/leaderboard/preview returns the top 10 advertising sponsors of the trailing 7 days for a chosen metric. Each row carries movement versus the equivalent 7-day window ending 30 days ago, in the same previous_rank / movement / rank_change vocabulary as the entity charts. Every caller gets the same board regardless of plan, so it needs no premium access — use it for public or signed-out surfaces, and GET /v1/podcasts/advertising/leaderboard (premium) for deeper pages, other time windows, and company or publisher filtering.

GET /v1/entities/search — new contained match quality

match_quality gains a value: contained marks a result whose whole name appears inside a longer query — a sign the query names that entity plus something else (spacex elon musk returns both Elon Musk and SpaceX as contained). These results rank alongside strong matches with popularity breaking ties, but don’t auto-select one: the unmatched remainder of the query usually names a second entity or a qualifier, so let the user pick. Existing integrations that only branch on exact are unaffected.

July 2026

Speaker roles — a documented, closed set (breaking change)

role on a speaker is now guaranteed to be one of fourteen values, listed in full under Episodes → Speaker roles. Previously the field could carry any of ~130 values, including one-offs and typos produced during transcript analysis; those are now normalized into the documented buckets on the way out (a REPORTER is served as CORRESPONDENT, a CALLER as AUDIENCE).
  • The episode list endpoints now apply the same default role filter as the detail endpoint. GET /v1/podcasts/episodes and GET /v1/podcasts/{id}/episodes previously embedded every speaker, while GET /v1/podcasts/episodes/{id} returned only conversation participants — the same episode gave two different answers. Both now return HOST, GUEST, PANELIST and CORRESPONDENT. If you were reading advertisers or soundbite speakers out of a list response, read them from GET /v1/podcasts/episodes/{id}/speakers?role=… instead.
  • role accepts every documented value. soundbite_speaker, narrator, announcer, voice_actor, moderator, audience, producer and other are now valid filter values; previously several roles appeared in responses but could not be filtered for.
  • role=unknown now works as documented. It returns speakers we could not identify, whether the underlying row records that explicitly or carries no role at all. It previously matched only the latter, missing almost every such speaker.
  • Role values are case-insensitive. ?role=HOST, ?role=host and ?role=HoSt are equivalent, on the REST API, in MCP tool arguments, and in alert speaker_roles. Responses continue to use uppercase. Alert speaker_roles previously rejected lowercase with a 422.
  • CO_HOST is retired. It was never produced after May 2026 and is now folded into HOST. Filtering on co_host is no longer accepted; use host, which covers both.

POST /v1/alerts/{id}/test-webhook — send a test webhook

A new POST /v1/alerts/{id}/test-webhook fires a synthetic alert.match.created delivery to every webhook connection on an alert, so you can verify your endpoint — receipt, signature, and parsing — without waiting for a real match. The payload is byte-for-byte shaped like a live delivery and carries the alert’s real id, title, kind, and first watched entity, with illustrative sample match content.
  • The webhook envelope gains a test boolean, set to true only on these test deliveries and absent on real matches, so your handler can exercise its parse-and-verify path while skipping real side effects. Existing consumers are unaffected — real matches never carry the field.
  • Nothing is persisted: a test never appears in the alert’s delivery log. The response reports each connection’s outcome (delivered, status_code, duration_ms, error); a non-2xx or unreachable endpoint comes back as delivered: false while the request itself still returns 200.
See Alerts → Webhooks → Send a test event.

June 2026

Alert filters — narrow what an alert surfaces

POST /v1/projects/{projectId}/alerts and PATCH /v1/alerts/{id} now accept a filters object that narrows matches after detection — applied identically to the matches list, the realtime email, and the daily/weekly digests. Four axes:
  • languages — restrict to source episodes in specific BCP-47-like language tags (e.g. ["en", "pt-BR", "zh-Hant"]). Empty (the default) keeps every language.
  • relevanceEVERYTHING (default) returns on-target and incidental matches; RELEVANT narrows to on-target only, dropping passing mentions.
  • source_popularityANY (default) keeps every match; POPULAR keeps only matches from the top 5% of currently-charting podcasts.
  • speaker_rolesPODCAST_SPEAKER alerts only. Replaces the default appearance set (GUEST, PANELIST, CORRESPONDENT, AUDIENCE, SOUNDBITE_SPEAKERHOST excluded). Sending this on an ENTITY_MENTION alert returns 422.
A PATCH with filters replaces the alert’s filter set wholesale — there’s no per-axis merge, so to add languages to an alert that already has relevance: "RELEVANT" you must send both. Send "filters": {} to clear every filter at once, or omit filters from the patch body to leave the existing set unchanged. Filters that narrow what gets detected (languages, speaker_roles) also gate the post-create historical backfill, so older matches that wouldn’t have passed the current filter were never stored — broadening either axis later won’t surface them. relevance and source_popularity are applied at read/delivery time, so the matches list and emails immediately reflect the change. Existing alerts keep their current behavior (no filters → every match surfaced). See Alerts → Filtering matches for the full spec and examples.

GET /v1/entities/search — purpose-built entity search (breaking change)

A new GET /v1/entities/search ranks people, companies, and knowledge graph entities for a free-text query — a name, partial name, nickname, stock ticker, @handle, or website domain — in one call. Each result is a discriminated union: type (person, company, or knowledge_graph_entity) says which kind it is, and exactly one of person/company/knowledge_graph_entity holds the matched record in the same compact shape those resources return elsewhere. Alongside it, match_quality and a mentions object (podcast_episodes, news_articles) help confirm the hit. Take the embedded record’s id (or slug) to the matching resource endpoint, or its id to alert creation.
  • The q= parameter on GET /v1/entities has been removed. Move name search to /v1/entities/search — passing q to GET /v1/entities now returns a 422 directing you there. GET /v1/entities still lists the most-mentioned entities and filters by type, podcast_id, or ids.
  • Search results are union-shaped (a person, company, or knowledge graph entity) rather than the always-an-entity shape GET /v1/entities returns — a match may be a person or company with no standalone entity, and vice versa.

GET /v1/podcasts/search now searches podcasts (breaking change)

As announced, GET /v1/podcasts/search now does what its name says: it searches podcasts by name and returns a ranked, paginated list of podcast objects. See Search.
  • If you used it to search episode dialogue (semantic_search / keyword_search), migrate to GET /v1/podcasts/episodes/search — the parameters and response shape are identical to what /v1/podcasts/search returned before this change.
  • GET /v1/podcasts?q=… keeps working and returns the same results as the new /v1/podcasts/search — it remains supported for backwards compatibility, but /v1/podcasts/search is now the canonical way to search podcasts, and the q parameter on /v1/podcasts may be retired in a future version.
  • Podcast search is metered as a standard endpoint — searching the catalog at /v1/podcasts/search now costs the same as /v1/podcasts.

Missing something? Email api@particle.pro.