include sections and modes never break an existing call. Renames and changes that could affect your integration are called out explicitly.
October 2026
Tools refuse arguments they do not take
Every tool now refuses an argument outside its input schema withinvalid_parameter, directly or through particle_call, instead of ignoring it. The error names the argument and where it belongs: semantic_search on particle_podcast_find_mentions points at particle_podcast_search_transcripts with company_slug or entity_slug, and a top-level sentiment reads pass it as speaker_statement_characteristics: {"sentiment": ["negative"]}. Before, such a call answered as if the argument were absent: semantic_search on find_mentions returned the subject’s every mention, unnarrowed. output_format stays accepted on every tool. A refused call is not billed.
Clearer refusals around speaker_statement_characteristics
speaker_statement_characteristicsaccepts a bare string for one label:{"sentiment": "negative"}reads as{"sentiment": ["negative"]}instead of failing to decode.- A refusal that carries its own fix no longer appends the generic “check the schema via particle_catalog” suggestion, which pointed agents away from the fix.
particle_podcast_search_transcripts’s characteristics refusals and its broadguest_filter refusal now say what to change, down to a narrower occupation.
How an episode was said
particle_podcast_get_episode takes include: ["speaker_statement_characteristics"] for an episode profile: the episode’s label shares per axis, one row per identified speaker with their pole-label shares, who stands out on each pole (“Most hedged”, “Most forward-looking”), and up to 5 of the strongest predictions, confident claims, criticism and optimism lines, each with its timestamp, moment link and labels. See Episode profiles.
How a show talks
particle_podcast_resolve takes include: ["speaker_statement_characteristics"]: each label’s share of the show’s scored lines over the last 365 days, and for pole labels the share of profiled shows with a lower share (“more forward-looking than 82% of shows”). See A show’s profile.
Compare how subjects are spoken of
New tool:particle_podcast_compare_share_of_voice answers “how is NVIDIA spoken of vs AMD vs Intel?” in one call. Pass two to five company_slugs, person_slugs or entity_slugs and an axis as by (default sentiment), and it returns one table row per subject with each label’s share of that subject’s scored lines. Each subject’s numbers equal particle_podcast_get_share_of_voice with the same arguments.
How a subject is spoken of, over time
particle_podcast_get_mention_trends in timeseries mode takes breakdown and speaker_statement_characteristics: each bucket’s mentions by sentiment, certainty, specificity or temporal orientation, or only the mentions said a certain way. A bucket on fewer than 20 scored mentions is marked low sample. Both need published_after, at most 365 days back.
The strongest mentions first
particle_podcast_find_mentions takes sort: "strength" with speaker_statement_characteristics. It puts the episodes whose mentions carry the labels most clearly first, each episode’s mentions strongest first: the most clearly negative takes on NVIDIA, or the most confident predictions about Ozempic. Only mentions that carry labels rank.
What was said, beside each share
particle_podcast_get_share_of_voice takes examples (0–3): it quotes that many lines under each group, or with breakdown under each of its labels, strongest first, with the speaker, the episode and a timestamp linked to the moment.
Statement-characteristics searches across languages find the best matches
particle_podcast_search_transcripts with speaker_statement_characteristics and a non-English language now returns the closest matching lines across all of that language’s podcasts, even when the query is written in another language. Before, an English query over Chinese podcasts could return nothing, and English queries over Spanish, German or French podcasts ran out of results early. Expect these calls to take a second or two longer.
The strongest lines, without a topic
particle_podcast_search_transcripts takes speaker_statement_characteristics with no semantic_search or keyword_search when it is scoped by episode_slug, speaker or a guest_ filter. It returns the strongest lines said that way, at most 50, and their Match row reads characteristics. See Without a topic.
How a subject is spoken of, counted
particle_podcast_get_share_of_voice takes breakdown, an axis as by, and speaker_statement_characteristics: how each occupation speaks of a company, how negatively it is spoken of overall, or who makes predictions about it. Label shares are of the scored lines, and a group on fewer than 20 is marked low sample.
How a person speaks, over time
particle_person_get_statement_characteristics shows how a person speaks on podcasts. It gives the share of their lines that are negative, neutral or positive; hedged, neutral or confident; vague, neutral or specific; and about the past, present or future. Shares are for the whole window and per week or month. include: ["examples"] adds each bucket’s strongest line for every outer label, with a link that plays it. The REST twin is GET /v1/people/{id}/statement-characteristics.
What experts said, and how they said it
speaker_statement_characteristics now combines with speaker and the guest_ filters on particle_podcast_search_transcripts, and with the guest_ filters on particle_podcast_find_mentions. Only the lines the selected people say count: guest_occupation: "cardiologists" with {"certainty": ["confident"], "temporal_orientation": ["future"]} finds confident predictions by cardiologists. See Filtering by characteristics.
Filter search and mentions by how each line is said
particle_podcast_search_transcripts and particle_podcast_find_mentions take a speaker_statement_characteristics object: {"certainty": ["confident"], "temporal_orientation": ["future"]} keeps confident predictions. Each axis is an array of its labels, and axes combine with AND. Put the topic in semantic_search and how it is said in the filter. Every matched or mention line then carries labels the filter accepts. See Filtering by characteristics.
Search and mention lines show how each line is said
particle_podcast_search_transcripts and particle_podcast_find_mentions end each line in topic and interview segments with its pole labels, for example _[confident · positive · future]_: sentiment (negative/positive), certainty (hedged/confident), specificity (vague/specific) and temporal orientation (past/future). _[neutral]_ marks a line that leans clearly on no axis; a line without brackets carries no labels. With output_format=json, each line has a speaker_statement_characteristics object with all four labels. See Speaker statement characteristics.
Share of voice counts guests by default
particle_podcast_get_share_of_voice now defaults to speakers="guests" and level="detailed". Hosts speak most of a subject’s mention lines and usually code to broadcasting, so the old all-speakers, major-group split mostly reported “media” whatever the subject. Each detailed group now shows the top-level group it sits under and that group’s share. With speakers="guests", the coverage in **Mentions:** is now of the guests’ lines rather than every line, so it no longer reads as low; a new **Hosts:** row says how many lines hosts spoke. Pass speakers="all" and level="major" for the previous split. The REST endpoint’s defaults are unchanged; its response adds speakers, speaker_mentions, host_mentions and each detailed group’s top.
Request a back-catalogue episode’s transcription
particle_podcast_request_transcription requests the transcription of an episode that particle_podcast_list_episodes marks requestable. It is billed exactly as POST /v1/podcasts/transcription/requests:
- The request that queues the episode is charged in USD at your plan’s transcription price, never drawn from your included requests, and needs overage billing turned on.
- A repeat, or an episode already queued or held, is billed as a lookup.
pp_ API key, or OAuth with the write scope.
particle_podcast_get_transcription_request is free and is the way to wait: poll it by request ID or episode until state reads transcribed, usually within 5 to 10 minutes. A tool that hits a back-catalogue episode’s transcript_not_available now names the request tool instead of saying a transcript needs an API key.
particle_company_get_podcast_ad_presence reads the company’s primary sponsor
particle_company_get_podcast_ad_presence reports the company’s primary sponsor: the one with the most ads naming the company. Before, it reported the most recently active sponsor with any ad linked to the company, so Shopify’s ad presence could come back as Toyota’s.
”New” in mention trends means a show started talking about the subject
particle_podcast_get_mention_trends and GET /v1/podcasts/mentions/by-podcast no longer call every show absent from the previous window new. That counted 3,983 of the 5,466 podcasts that mentioned Walmart over October 1 to 23, mostly one-off mentions and shows Particle had only just started tracking.
A show that mentioned the subject in the current window only is now judged against a lookback before it: lookback_days, default 90, echoed as lookback_start. It gets the first label that applies:
newly_tracked: too little published history to tell.returning: it mentioned the subject earlier in the lookback.passing: a single mention line.new: two or more lines and none in the lookback.
new_podcastsis much smaller: 529 rather than 3,983 for Walmart. The newreturning_podcasts,passing_podcastsandnewly_tracked_podcastscount the rest.changetakes three new values,returning,passingandnewly_tracked, and rows carry them. A client that checkschangeagainst a fixed list will see values it doesn’t know.- The old meaning of
newis no longer one filter. It isnew,returning,passingandnewly_trackedtogether. change=newandchange=returningsort by popularity whensortis unset, so the notable shows lead. Every other list still sorts bymentions.
Chart debuts, and fast chart history
particle_podcast_get_rankings mode=movers takes change=debut for shows on a chart slot for the first time since tracking began (May 2026), and change=reentry for returning shows. new still returns both, and most of its entries are established shows returning. Each entry is labeled debut (with its episode count and, when the catalog holds the whole back catalog, its first-episode date) or re-entry (with the date it first charted).
mode=history with podcast_slug now defaults country to us and spans both sources; pass country for another market. A popular show’s three-month history now returns in well under a second instead of 10–20 seconds.
A guest’s pitch list is screened
particle_podcast_get_guest with include: ["recommended_podcasts"] leaves out three kinds of show:
- shows the guest already appeared on, including under another record of the same identity, and same-host sibling feeds of those shows;
- shows that stopped publishing;
UNSAFEshows.
Co-advertisers name other brands
particle_company_get_podcast_ad_presence with include=["co_advertisers"] used to pair a company with its own sponsor aliases (BetterHelp came back as “Mind If We Talk × BetterHelp”). It now ranks the other brands whose ads air in the same episodes, by shared episodes and shared podcasts, one row per brand, as a numbered list. Rows add shared_podcasts. sponsor_a is always the queried company. The REST GET /v1/podcasts/advertising/co-occurrence endpoint’s company_id filter works the same way.
Faster meaning-search trends and expert-filtered searches
particle_podcast_get_episode_timeseries with a broad semantic_search (such as “AI agents” over three months) answers instead of timing out. When the topic matches more segments than it can count in time, the response adds a **Counts:** row (saturated: true in JSON) saying the counts are lower bounds. particle_podcast_search_transcripts with a broad guest filter, such as guest_occupation: "physicians" with guest_practicing: true, now returns in seconds rather than hitting the time limit. A request that does run out of time fails once with request_timeout instead of being retried.
A question’s constraints go on the first search
particle_podcast_search_transcripts and the server instructions no longer say to search with semantic_search alone and add filters later. Agents followed that literally: they resolved “medical professionals” to an occupation code, searched without it, and answered from whoever spoke. Now the constraints a question states (who is speaking, which person, company or show, the window, the language) go on the first call, and only filters an agent adds on its own wait until a search shows coverage. The speaker filter takes the question’s own word (guest_occupation: "founders" is the capacity, "VCs" the field), so it goes on that first call without waiting for a lookup; agents that ran particle_expertise_resolve beside the search dropped the filter. Two groups of speakers (“founders and VCs”) take one call each, since the guest_ filters AND together. When particle_expertise_resolve finds no code, it now says to rephrase the words in occupational terms or browse with parent before going on without the filter.
Bad cursors and filters that match nothing are errors
Acursor that no response returned fails with invalid_parameter instead of restarting at the first page. A podcast, episode, company, entity, publisher, or topic filter that matches nothing fails with unresolved_reference, as the search tools already did, instead of an empty listing: resolve the value and retry. particle_podcast_get_rankings in movers mode now pages: it returns cursor when there are more movers, and takes it.
particle_podcast_get_share_of_voice now fails with unresolved_reference for a podcast_slug or publisher_slug that matches nothing, as it already did for an unknown subject, instead of returning an empty split.
Podcast external links list only the show’s own verified presences
include: ["external_links"] on the podcast tools no longer lists LinkedIn for a show, or placeholder links such as not_found, and returns working URLs for handles that carried invisible characters.
Tool display titles
MCP discovery includes a human-readabletitle for every tool. Clients can show these labels in tool pickers and approval prompts. Tool names and inputs are unchanged.
Error suggestions name tools, not REST paths
When an error points at a lookup that no tool performs, the suggestion keeps its guidance and leaves out the REST path an MCP client cannot call. Suggestions that point at transcript search, mention search or chart rankings now nameparticle_podcast_search_transcripts, particle_podcast_find_mentions or particle_podcast_get_rankings.
Search the lines a person said with particle_podcast_search_transcripts
particle_podcast_search_transcripts takes speaker, a person slug from particle_person_resolve. It keeps only passages in which that person speaks a line that carries the query (a quote split across their consecutive lines counts), and only their lines are matches: what they said, not what was said in an episode they were on. A soundbite of them on another show does not count.
Transcript ranges and speakers on particle_podcast_get_episode
Withinclude: ["transcript"], particle_podcast_get_episode returns every line that overlaps transcript_start–transcript_end. Before, a short range inside a long line came back empty. transcript_speaker also takes a person slug, as the episode’s speakers list returns it.
Moment links
particle_podcast_search_transcripts, particle_podcast_find_mentions and particle_podcast_list_clips link each timestamp to the moment on Radar, as [87s–142s](https://radar.particle.pro/podcasts/…/episodes/…?t=87.2), and a search match has a **Link:** row in both formats. Cite that link and a reader lands on the exact quote. With output_format=json the same links arrive as url fields. See Moment links.
Find a topic by name
particle_topic_browse takes query. It returns topics whose names match: exact names first, then prefixes, then substrings, each by story coverage. With parent_slug, the search covers that subtree. An agent no longer has to walk the tree from the roots to find a topic slug.
A short semantic search on one show says when keyword_search finds it
Whenparticle_podcast_search_transcripts with a one-word semantic_search and a podcast_slug comes back empty while the show does say the word, the error is now weak_semantic_match. Its example retry adds the word as keyword_search and keeps podcast_slug. The podcast_slug and episode_slug remedies no longer claim the show or episode never discusses the topic when only the relevance cutoff was missed.
Share of voice for a keyword
particle_podcast_get_share_of_voice takes keyword_search as a subject: “who is talking about prior authorization?” splits the lines that say the words by the speakers’ occupations or fields, counting a line only when its own speaker said every word. Its window is at most 90 days. particle_podcast_get_episode_timeseries now says plainly that its guest_ filters are episode-level: with keyword_search they count matching segments in episodes with such a guest, whoever spoke them.
Expertise beside every speaker
particle_podcast_search_transcripts (full format) and particle_podcast_find_mentions (summary and detail) now list each identified speaker before the lines, as **Speaker:** Name (slug, ROLE) — Title (code) · standing · seniority. particle_podcast_get_episode appends the same read to each speaker. particle_podcast_list_guests carries it on every row; include: ["expertise"] widens it with the organization. An agent can now check a speaker’s credentials and pass their codes straight to guest_occupation or guest_field.
The server instructions and tool descriptions now say plainly how to answer a question about who is speaking:
- Resolve the words (“doctors”, “economists”, “people in finance”) with
particle_expertise_resolvefirst, then filter by the code. Never rely on search wording. - On
unresolved_reference, resolve and retry. Never drop the filter. guest_filters pick episodes or segments, not each line’s speaker, so timeseries counts are not what the experts said.- A tool
particle_cataloglists but a stale tools/list lacks is called throughparticle_call.
Occupation groups, and corrections for a value that matched nothing
guest_occupation, occupation and particle_expertise_resolve take SOC 2018 groups and everyday names: physicians covers all 13 physician specialties, and doctors, medical-professionals, nurses, professors, journalists and more stand for the occupations people mean by them. particle_expertise_resolve with parent browses through the groups: a SOC major group such as 29-0000 now lists its minor groups rather than its detailed occupations. When a slug, occupation or field matches nothing, the error now names the exact particle_*_resolve call that finds valid values and, where it can, the closest matches.
Words that name a field or a capacity, and guest_capacity
guest_occupation and occupation take words no occupation answers well: oncologists filters by field 3211 Oncology, investors by field 350208, and founders or politicians by the capacity executive_founder or public_official. particle_expertise_resolve leads with a capacity section when the query names one, with the parameters that take it. A new guest_capacity filter on particle_podcast_find_mentions, particle_podcast_list_episodes, particle_podcast_search_transcripts and particle_podcast_get_episode_timeseries keeps guests who know their field in that capacity.
Current team on particle_person_get
particle_person_get with include: ["sports"] leads with a **Current team:** row for NFL, MLB and NHL players, from the league’s current roster, read daily. It is the only part of the section that says where a player is today.
Speaker expertise
Three new tools answer who knows what, who books them, and who is talking:particle_expertise_resolve(free) turns free text into SOC 2018 occupation and ANZSRC 2020 field-of-research codes, and walks their hierarchy withparent.particle_expertise_getdescribes one code and, withinclude: ["top_guests"]or["top_podcasts"], ranks the guests booked under it and the shows that book them over a window of up to 90 days, optionally established guests only.particle_podcast_get_share_of_voicesplits a person’s, company’s or entity’s mentions by the speakers’ occupations or fields over a window of up to 365 days.
particle_podcast_find_mentions, particle_podcast_list_episodes, particle_podcast_search_transcripts and particle_podcast_get_episode_timeseries take guest_occupation, guest_field, guest_standing, guest_seniority, guest_practicing and guest_in_field; on find_mentions they keep only the lines a matching guest spoke. On the timeseries, guest_occupation and guest_field count as a subject. particle_podcast_list_guests takes occupation, field, standing, seniority, practicing, capacity, employer, appeared_since and include: ["expertise"] in directory mode. A filtered directory keeps one-off guests, podcast_slug with a filter lists that show’s guests through the directory, and a filter with mode="trends" returns invalid_input. particle_podcast_resolve takes guest_occupation, guest_field, min_established_guest_share, min_in_field_guest_share and max_promotional_guest_share, plus include: ["guest_expertise"] for a show’s guest mix. particle_person_get accepts include: ["expertise"], particle_podcast_get_guest include: ["in_field_appearances"], and particle_podcast_get_episode include: ["guest_expertise"].
An occupation or field passed as a parameter that names nothing returns unresolved_reference with did-you-mean suggestions and a pointer to particle_expertise_resolve; an unknown code on particle_expertise_get returns not_found with the same suggestions. The /plugins connection does not carry the three new tools or the expertise filter parameters; it does advertise the new include values. Calls that set none of the new parameters return what they did before.
Sports history on particle_person_get
particle_person_get accepts include: ["sports"]: the sports an athlete or coach plays, the teams they played for or coached with years and the team’s leagues, and leagues recorded on the person directly, from Wikidata. Team and league entity slugs work with particle_entity_get. particle_person_get now also rejects an unknown include value with an invalid_parameter error instead of ignoring it.
Compact metadata for plugin packages
The/plugins connection now publishes shorter instructions and descriptions so clients with tool metadata budgets can expose all 36 operations. Tool names, input constraints, safety annotations, access checks, and execution behavior are unchanged; the standard endpoint keeps its full descriptions.
Fixed tool surface for plugin packages
The new/plugins connection exposes a fixed set of 36 named operations for plugin packages. Its advertised and executable tools match; particle_alert_create, particle_alert_update, particle_call, particle_catalog, and future unlisted operations are unavailable. Query and header selectors do not change this set. The standard endpoint keeps its existing selector and dispatcher behavior. The connection reuses the existing OAuth resource and tool annotations. Tool execution requires an existing eligible account outside its convertible credit/trial phase, and per-request payment credentials are rejected. Established account usage pricing and previously enabled overage still apply. See Tool sets and discovery before migrating a package after deployment.
September 2026
Untranscribed episodes say so, and queued
Tools that read what an episode’s transcript produced, such as particle_podcast_list_related_episodes, answer a back-catalogue episode with error code transcript_not_available instead of not_found: the episode exists, but has not been transcribed. transcript_status gains queued, for a back-catalogue episode whose transcript has been requested and is waiting to be transcribed.
Coverage on particle_podcast_resolve
particle_podcast_resolve accepts include: ["coverage"]: how many of the show’s episodes we know of, by transcript status and by year, and whether its back catalogue has been imported and is complete.
Transcript status and the back catalogue
particle_podcast_list_episodes accepts transcript_status (any, transcribed, untranscribed, requestable); with podcast_slug, the first, third and fourth also list the show’s back catalogue, older episodes discovered in its feed but not transcribed. Episodes that are not transcribed render a **Transcript:** row saying where they stand. particle_podcast_get_episode returns a back-catalogue episode’s feed metadata instead of failing, and skips its transcript-derived sections. Calls without transcript_status return what they did before.
Paste a Particle link in place of a slug
Everyepisode_slug input now accepts a particle.pro or Radar episode link — https://particle.pro/episode/<episode> (the form alert emails carry) or https://radar.particle.pro/podcasts/<show>/episodes/<episode>. Every podcast_slug input accepts a particle.pro or Radar show link — https://particle.pro/podcast/<show> or https://radar.particle.pro/podcasts/<show> — and a Radar episode link resolves to its show. A link a user copied from Radar or an alert works as-is. The exact-match slug filter on particle_podcast_resolve is unchanged. Links to other sites (Apple Podcasts, Spotify, YouTube) are not parsed. Slugs and IDs resolve exactly as before.
Keyword alerts
particle_alert_create, particle_alert_preview and particle_alert_update accept kind: "KEYWORD_MENTION" with a keyword in place of entities, for names that have no entity slug or whose entity has no podcast coverage. The phrase matches the way a double-quoted keyword_search phrase does on particle_podcast_search_transcripts. entities is no longer required on create and preview; it is still required for the entity kinds, a missing keyword on a keyword alert returns a missing_parameter error, and a phrase that matched more than 700 episodes in the past week returns unprocessable_entity.
A verbatim quote on each clip
Clips now carryquote: one line of 140 characters or fewer, taken word for word from the transcript and spoken by the clip’s speaker where possible. It rides the clip everywhere a clip appears: particle_podcast_list_clips, the clips on particle_podcast_get_episode, and the overlapping clips on particle_podcast_search_transcripts. A pull quote no longer needs a clip transcript read. Clips without a quote omit the field.
Alert creation discloses its billing effect
particle_alert_create now advertises destructiveHint: true and explains that creating an active alert can move an eligible organization from credit/trial billing to paid fixed-fee billing. Its description asks clients to explain this effect and obtain explicit confirmation first. Creating a paused alert does not trigger this transition. This corrects the metadata for existing behavior; it does not change billing execution or add server-side confirmation enforcement.
Explicit tool safety annotations
Every tool now advertises explicitreadOnlyHint, destructiveHint, and openWorldHint values, including false values, for clients that require complete safety metadata. Alert updates are marked destructive because they can replace existing configuration. Alert previews are marked non-read-only because they start a background sweep and cache its results, without creating an alert or sending notifications. Tool execution, OAuth scope requirements, billing, and response formats are unchanged.
Compact search and mention results for screening
particle_podcast_search_transcripts and particle_podcast_find_mentions take format: "compact". A compact search page carries the same ranked matches with no dialogue windows or clips — episode and podcast slugs, segment id and span, segment type, the segment’s one-line description, and the relevance score — and skips the transcript load and line scoring that produce windows, so it is a fraction of the size and returns sooner. Compact mentions list, per episode, the mention count, the strings the entity was mentioned as, and the segments carrying the mentions, with no lines. Both are for fanning out over many companies, themes, or dates and deciding where to read before reading anything. Default responses are unchanged, except that every search match now also carries - **Segment id:** and - **Segment span:** rows and the - **Match:** row shows the relevance score, so a match can be cited and its dialogue fetched later.
Look up a person or company by any identifier
GET /v1/entities/lookup resolves an external identifier — a LinkedIn slug, a social handle, a company domain, a ticker, an SEC CIK, a Wikidata QID — to the people and companies that carry it, up to 100 per call. It is the reverse of the external-links endpoints. You do not have to normalize the identifier: a bare handle, the stored form, and a pasted profile URL all resolve, and the input is echoed back exactly as sent.
Results carry a matches array rather than one entity, because an identifier is not unique to an entity — two records for the same real person can each carry the same LinkedIn profile. match_count reports how many carry it.
Company external links
GET /v1/companies/{id}/external-links lists every third-party identifier a company carries — LinkedIn, social profiles, its domain, tickers, SEC CIK, and Wikidata QID — matching the endpoint people have had. The same list rides GET /v1/companies/{id}, and particle_company_get exposes it as include: ["external_links"].
Embedded Radar cards
particle_radar_render_cards presents up to six selected episode, podcast, company, or person results as linked cards. Advertise it with ?include=radar or ?include=all. Rendering is free and does not fetch or store data. The server now exposes a static MCP Apps HTML resource through resources/list and resources/read; the renderer returns structured cards plus a complete Markdown fallback. Existing data-tool response formats are unchanged.
x402 discovery lists every tool price
mcp.particle.pro/.well-known/x402.json (and the API host’s copy) now itemizes per-tool prices under mcp.tools — one row per payable tool with its name, summary, price and network — and the manifest at /.well-known/x402 carries the same list under tools on the MCP resource. Free tools and the alert tools, which need an account, are not listed.
particle_podcast_list_related_episodes — tidier sets
At most two episodes per show, the same content republished on another feed collapsed to one row, and feeds flagged as machine-made or syndication spam excluded; episodes of removed shows no longer appear without a podcast.
Setup playbook, endpoint map, and fuller initialize instructions
mcp.particle.pro/agents.md (also on the API host, and as the Agent onboarding page) is the playbook an agent follows to connect a client and run a first query: per-client configuration for Claude, Claude Code, Cursor, VS Code, Codex, ChatGPT, Windsurf, and Zed, the restart most clients need before new tools appear, and what to do on a 401, 403, or 404. Paste “Read https://api.particle.pro/agents.md and connect me to Particle” into any coding agent. mcp.particle.pro/llms.txt lists every tool by category with its documentation page and per-call price, next to every REST endpoint.
The instructions the server returns on initialize now carry the complete conventions rather than a summary: how errors course-correct (the **Error code:** line, re-resolve on 404, never retry-loop internal_error), the ?include= selector for opt-in categories, format="detail" on particle_podcast_find_mentions, particle_podcast_list_episodes for filter-driven discovery, keyword_match="ranked", and include: ["recommended_sponsors"]. The same text opens the docs index and the endpoint map, so what an agent reads in any of the three places is identical.
x402: per-tool prices, free handshake
KeylessPOST /mcp is now priced per tool call: each tools/call costs that tool’s per-call price (from $0.01), `initialize`, `tools/list` and `ping` are free, and a batch costs the sum of its tool calls. Previously every POST cost a flat $0.01.
Pay per request with x402 — keyless POST /mcp
A keyless POST to the MCP endpoint now returns 402 with two challenges instead of a bare 401: the x402 payment requirements in PAYMENT-REQUIRED (a flat $0.01 in USDC on Base per HTTP request) and the usual WWW-Authenticate: Bearer … resource_metadata="…" pointer for OAuth clients. An agent with a funded wallet can pay per request and call any payable read-only tool without an account (project-scoped tools such as the particle_alert_* family still need a credential); a paid request skips the bearer requirement and is served exactly as a keyed one. OAuth and API-key traffic is unchanged — any presented credential takes the normal auth path. See Pay per request with x402.
Related episodes — particle_podcast_list_related_episodes
A new standard-tier particle_podcast_list_related_episodes answers “who else covered this”: episodes from other shows on the same story or subject as an episode, best first, each with a score, a band, and — with include: ["basis"] — the shared entities, topics, news story, guests and days apart. published_within_days narrows to a recency window and same_podcast opts the source show in. Not a topic search (particle_podcast_search_transcripts) or a mention list (particle_podcast_find_mentions). The REST counterpart is GET /v1/podcasts/episodes/{id}/related.
Related podcasts — particle_podcast_list_related and include: ["related"]
A new standard-tier particle_podcast_list_related answers “shows like this show”: the shows most related to a podcast, best first, each with a calibrated score, a band (strong / moderate / weak) to branch on, and — with include: ["basis"] — the signals behind the pairing (content similarity of recent episodes, shared topics, named shared guests, same publisher, shared sponsors). Related sets are precomputed per show and restricted to its language; a show whose set has not landed yet returns an empty list rather than an error. particle_podcast_resolve gains include: ["related"] for the five most related shows inline. Slugs are edges as always: every related show feeds the podcast tools, and the people and topics in the basis feed the guest and resolve tools. The REST counterpart is GET /v1/podcasts/{id}/related.
Sponsor prospecting — include: ["recommended_sponsors"] on particle_podcast_resolve
particle_podcast_resolve takes include: ["recommended_sponsors"] (premium-grade) to attach the five advertisers a show could pitch: sponsors that run on its related shows but not on it, each with the linked company, a score, a band, how many related shows run it, its ads and most recent ad across them, and which shows. The paged form is GET /v1/podcasts/{id}/recommendations/sponsors.
Guest recommendations and inline related episodes — new include values
Three of the get/resolve tools gain an inline section, so the common follow-up needs no second call: particle_podcast_get_episode takes include: ["related"] for the five episodes from other shows most related to the one you have; particle_podcast_get_guest takes include: ["recommended_podcasts"] for the five shows a person could plausibly appear on next — shows related to the ones they have guested on, minus those, with the venues behind each pick (the pitch list); and particle_podcast_resolve takes include: ["recommended_guests"] for the five guests a show could book that it hasn’t — people booked by its related shows, with how many and which (the booking pipeline). Each section is present even when empty, with a note saying why, so an honoured-but-empty include is distinguishable from one not requested. The paged REST forms are GET /v1/podcasts/guests/{id}/recommendations/podcasts and GET /v1/podcasts/{id}/recommendations/guests.
Include values are now validated on these three tools. An unknown value in include on particle_podcast_resolve, particle_podcast_get_episode or particle_podcast_get_guest returns an invalid_parameter error naming the accepted values, where it was previously ignored. Calls that pass documented values are unaffected.
Segments carry transcript line ranges, and the tiling claim is corrected
Segments now reportstart_line and end_line — 1-indexed inclusive transcript line
numbers — on particle_podcast_get_episode with
include: ["segments"], and on GET /v1/podcasts/episodes/{id}/segments,
GET /v1/podcasts/segments, and GET /v1/podcasts/segments/{id}. They match the number
field on each line of GET /v1/podcasts/episodes/{id}/transcript, so a transcript can be
sliced by segment exactly instead of by arithmetic on float timestamps.
A documentation correction ships with them. These docs and the
particle_podcast_search_transcripts tool description previously said segments “tile an
episode end-to-end” and that “every minute belongs to exactly one segment.” That was wrong,
and it is the reason a segment’s end_seconds does not equal the next segment’s
start_seconds. Segments are contiguous in transcript lines, not in wall-clock seconds:
start_seconds is when a segment’s first spoken line begins and end_seconds is when its
last spoken line ends, so consecutive segments are separated by whatever silence sat between
those two utterances — usually a fraction of a second, occasionally minutes of music or an
ad-stitch window. On episodes reporting start_line/end_line, those intervals contain no
transcribed speech and nothing is omitted from them; see the caveat below for older
episodes.
No existing data changed — this is what segments produced by the current segmenter have
always been, now described accurately and made checkable. start_line/end_line are recorded on newly segmented
episodes and omitted on everything segmented earlier; backfilling them across the historical
corpus is a follow-up and has not shipped.
Two different dates are in play here, and conflating them would be misleading:
- Line-range persistence starts with this release. Every episode segmented before it
omits
start_line/end_line, however healthy its coverage is. - Coverage was fixed on 24 July 2026. Episodes segmented before that came from a version of the segmenter that could genuinely leave transcript lines in no segment, and about 11% of them did. A repair of that cohort is in progress.
start_line/end_line does not by itself mean an episode has gaps —
the large majority of episodes without them were segmented after the coverage fix and are
complete. It only means the partition cannot be verified from the response alone. Where that
matters, check the episode transcript directly.
August 2026
Alerts watch exactly one entity
An alert now watches a single entity:particle_alert_create, particle_alert_update, and particle_alert_preview accept exactly one slug in entities, and passing more than one returns an invalid_parameter error telling you to create one alert per entity. The REST endpoints (POST /v1/projects/{projectId}/alerts, PATCH /v1/alerts/{id}, and the preview) enforce the same maxItems: 1. Alerts created before this rule keep their multi-entity watch list and keep matching and delivering; the next write to their entities field must name a single entity.
Separately, advertised tool input schemas now carry the numeric and array bounds the server already enforced — minimum/maximum (e.g. window_days 1–30) and minItems/maxItems — across every tool, so agents can self-correct before a failed call instead of after.
Semantic trend counting on the episode timeseries
particle_podcast_get_episode_timeseries takes semantic_search — the counting twin of particle_podcast_search_transcripts’ semantic query, using the same embedding and similarity threshold so the counts agree with search results. “How often do podcasts discuss weight-loss drugs, per week” is now one aggregated call instead of paging search once per period. It adds the same per-bucket mention_count and range total_mentions that keyword_search produces; the two cannot be combined, and semantic_search requires published_after (ranges up to ~2 years). The REST endpoint GET /v1/podcasts/episodes/timeseries gained the matching semantic_search query parameter.
Keyword search now filters instead of only ranking
keyword_search on particle_podcast_search_transcripts and GET /v1/podcasts/episodes/search used to be a ranking signal: the words nudged relevance but nothing was excluded, so a hybrid call could return passages containing none of the words you typed. It is now a filter — every word must appear in the matched passage — which also means a hybrid call is the intersection of semantic_search and keyword_search rather than a blend of both.
This changes results for existing calls. A search for QuillBot that returned 100 passages now returns the 21 that actually say “QuillBot”; the rest were semantic neighbours. Where keyword_search is a loose bag of related words that will not co-occur in one passage, the new keyword_match: "ranked" restores the previous behavior. Quoted phrases are unchanged — they have always been exact.
Searches that return nothing now say why
An empty search used to be indistinguishable from “we have no such content”, which left agents unable to tell an over-specified query from an empty corpus. Both surfaces now report the cause, measured by re-running the query with each filter removed in turn.GET /v1/podcasts/episodes/search returns a diagnostics object on an empty page, naming the filter that excluded everything, why it did, and a retry_with parameter delta. particle_podcast_search_transcripts turns the same finding into an actionable error carrying the corrected call, so an agent can retry directly. When the query text genuinely matches nothing, that is still an ordinary empty result rather than an error.
Entity and role filters cover the whole corpus
entity_slug / person_slug / company_slug / role / entity_type filters were resolved against at most 1,000 episodes per entity. For anything widely discussed that was a small, arbitrary slice — Andy Burnham appears in 10,418 episodes, and 90% of them could never be returned. These filters now run natively against the full index, so a filtered search sees every episode. particle_podcast_search_transcripts also gained entity_type, for “discussions of X that mention some book”.
Unresolvable references are rejected, not ignored
Passing a name that matches nothing —company_slug: "x" — used to either empty the results or be silently dropped, depending on whether another parameter happened to resolve. It now returns an unresolved_reference error naming the parameter and the resolve endpoint to call.
Lighter search responses
Search results embedded the parent episode three times per match (once at the top level, once under the segment, once per clip). The redundant copies are gone; the episode on each match is unchanged. If you readsegment.episode or clips[].episode out of a search response, read the match’s own episode instead.
Language filter across the podcast tools
particle_podcast_find_mentions and particle_podcast_search_transcripts take a language filter — a two-letter ISO 639-1 code (e.g. "fr") restricting results to episodes of podcasts in that language. “Mentions of Sam Altman on French-language podcasts” is now one call: {"person_slug": "sam-altman", "language": "fr"}. The existing language filter on particle_podcast_list_episodes and particle_podcast_get_episode_timeseries was upgraded from an exact tag match to the same semantics: values are validated (an unknown code is an actionable error rather than a silent empty result) and matched on the podcast’s primary language subtag, so fr covers fr-FR and fr-ca. The REST endpoints GET /v1/podcasts/mentions, GET /v1/podcasts/mentions/timeseries, and GET /v1/podcasts/episodes/search gained the matching language query parameter, with the same subtag semantics applied to the existing filter on GET /v1/podcasts and GET /v1/podcasts/episodes.
company_slug now carries the knowledge-graph slug
particle_podcast_get_sponsors, particle_podcast_get_sponsor_leaderboard, and particle_company_get_podcast_ad_presence used to put a domain-preferred identifier in company_slug (e.g. okx.com). company_slug now carries the actual knowledge-graph slug (e.g. okx), and the previous domain-preferred value moved to a new company_id field — both are valid /v1/companies/{id} keys, but company_slug is the stable one. If your agent parses company_slug out of any of those tools’ JSON output, expect a different value. The rendered markdown still shows company_id, because a domain like okx.com stays recognizable where a generated entity slug can be huntchef-g-11j62z1w0g. The REST endpoint behind the ad-presence tool, GET /v1/companies/{id}/podcast/advertising, gained the matching slug field. particle_podcast_get_episode_ads and its REST endpoint GET /v1/podcasts/episodes/{id}/ads now populate company.slug alongside the existing company.id.
Clips filter by speaker
particle_podcast_list_clips takes a speaker filter: a person slug (from particle_person_resolve), a knowledge-graph entity slug for the same person, or an ID. The listing then returns only clips whose primary speaker is that person — “an insightful Sam Altman clip” is now one call: {"speaker": "sam-altman", "type": "INSIGHTFUL"}. A speaker — or podcast — reference that resolves to nothing now returns an empty listing rather than silently widening back to the full catalog. The REST endpoint GET /v1/podcasts/clips gained the matching speaker query parameter.
July 2026
Speaker roles — a documented, closed set
Everyrole an episode or transcript tool returns is now one of fourteen documented
values — see Episodes → Speaker roles. Previously
the field could carry any of ~130 values produced during transcript analysis; those
are now normalized into the documented buckets on the way out, so an agent can branch
on role without a catch-all.
Role arguments — role on the episode and mention tools, speaker_roles on the alert
tools — are now case-insensitive, so echoing back a value in the casing it appeared in
prose no longer fails validation. CO_HOST is retired and folds into HOST.
Ad timeseries scopes to a show or a network
particle_podcast_get_ad_trends in timeseries mode now takes podcast_slug and publisher_slug, so a company’s ad volume can be charted on one show or across one publisher’s catalog instead of the whole corpus. Both accept a slug or an ID, matching the same filters on the mentions timeseries — which is what makes organic mentions and ad reads comparable under one scope. A reference that resolves to nothing returns zero-filled buckets rather than silently widening back to the full corpus. Omitting both preserves the previous behavior. The REST endpoint GET /v1/podcasts/advertising/timeseries gained the matching podcast_id and publisher_id query parameters.
REST parity: five new tools and six expanded ones
The MCP surface now covers every public GA REST capability. Five new tools:particle_podcast_get_episode_timeseries— time-bucketed episode and mention counts with the same filters asparticle_podcast_list_episodespluskeyword_search; the purpose-built answer to “how often is X discussed over time”.particle_podcast_list_clips— browse highlight clips by podcast, type, or engagement score, with aclip_iddetail path andinclude=["transcript"].particle_podcast_get_episode_ads(premium) — every detected ad read inside one episode with sponsor, product, offer, read type, placement, and exact offsets.particle_podcast_get_ad_trends(premium) —sponsor_trends(advertisers ramping up or pulling back) andtimeseries(one company’s ad volume over time, split host-read vs pre-recorded).particle_entity_get— a knowledge-graph entity’s profile, closing the loop forplace/otherslugs fromparticle_entity_resolve.
particle_podcast_list_gueststakespodcast_slugfor one show’s guest roster (one-off guests included).particle_podcast_get_rankingsaddsmode=slots— every valid source, country, andcategory_slugwith live chart data, so filter values are discovered rather than guessed.particle_podcast_get_publishertakesqueryto resolve a publisher name to a slug in the same call (candidates on ambiguity). The RESTGET /v1/podcasts/publisherslisting gained the matchingqfilter.particle_podcast_get_sponsor_leaderboardaddsmode=publishers(the sell-side leaderboard withunique_sponsorsandads_per_active_podcastmetrics) and apublisher_slugfilter for sponsors mode.particle_company_get_podcast_ad_presenceaddsinclude=podcasts(full ranked show list),include=segments(actual ad-read segments with AI summaries), andinclude=co_advertisers(sponsor pairs sharing episodes).particle_podcast_get_episodecross-references the new episode-ads tool.
Premium include sections now honor the plan’s premium entitlement
The include sections that carry premium-grade data on standard-tier tools now require a plan with premium endpoints, matching the premium-tier tools themselves:suitability and rankings on particle_podcast_resolve, and bias, suitability, and advertising on particle_podcast_get_publisher. Entitled plans are unaffected. A plan without premium endpoints now receives a premium_required error naming the offending include values — retry without them for the standard sections (the high-level suitability_tier and bias enums on resolve results are standard data and always rendered).
Filter-aware alert previews
particle_alert_preview now accepts the same filters object as particle_alert_create, so the match-frequency estimate reflects what the alert would actually surface once its filters are applied. languages and speaker_roles narrow the historical sweep exactly; relevance and source_popularity are graded at read time and don’t run on historical episodes, so they leave the count unchanged (the estimate is an upper bound when relevance=RELEVANT). The preview cache key keys on the count-affecting filters — changing languages or speaker_roles starts a fresh sweep, while toggling relevance or source_popularity returns the same cached count. Omitting filters preserves the previous unfiltered behavior.
June 2026
Alert filters — narrow what an alert surfaces
Alerts now carry a persistentfilters object that narrows what gets surfaced — applied identically to the matches list, the realtime email, and the daily/weekly digests. Four axes: languages (BCP-47 tags), relevance (EVERYTHING vs RELEVANT), source_popularity (ANY vs POPULAR = top 5% of currently-charting podcasts), and speaker_roles for PODCAST_SPEAKER alerts (defaults to GUEST,PANELIST,CORRESPONDENT,AUDIENCE,SOUNDBITE_SPEAKER; sending it on an ENTITY_MENTION alert returns an unprocessable_entity error).
particle_alert_create and particle_alert_update accept the filters object directly, and particle_alert_get / particle_alert_list echo the active filter set back so reads expose the current state. Update semantics mirror entities/notifications: passing filters on update replaces the whole set, {} clears all four axes, and omitting it leaves the existing set unchanged. See Alerts → Filtering matches for the per-axis spec and the REST changelog for the wire shape — the same filter object is accepted on POST /v1/projects/{projectId}/alerts and PATCH /v1/alerts/{id}.
Better entity & person resolution
particle_entity_resolveandparticle_person_resolvenow rank across people, companies, and knowledge graph entities with one relevance model (exact name / identifier / known alias → prefix → all-words → fuzzy), replacing the prior name-only substring match. Results are better-ordered and tolerate typos, stock tickers,@handles, and domains.particle_person_resolvealso now finds people who aren’t yet linked to a knowledge-graph entity. Each match carries the canonicalslug,name, anddescription(plus a company’scompany_domain) — enough to confirm the hit and traverse to the matchinggettool.
Alerts
- Seven alert lifecycle tools — a new default
alertscategory brings the Alerts feature to the MCP surface:particle_alert_create,particle_alert_list,particle_alert_get,particle_alert_update,particle_alert_delete,particle_alert_preview, andparticle_alert_list_matches. Watch a person, company, or other entity and get emailed whenever it’s mentioned on a podcast (ENTITY_MENTION) or appears as a speaker (PODCAST_SPEAKER); preview match frequency before committing; and review the matches an alert has caught. - The first writable tools —
particle_alert_create/particle_alert_updatemutate andparticle_alert_deleteis a destructive soft delete, so these are notreadOnlyHint: true. They act on the single project your credential is scoped to — there is no project parameter and no way to reach another project’s alerts. Watch targets are passed as the same entity slugs the resolve tools return (resolve a name once, then watch it).
Richer external links
- External-link attributes in markdown — when
particle_podcast_resolvehydratesinclude: ["external_links"], each platform bullet now appends the attributes the platform reports (audience size, content tallies, verified status, …), so a YouTube channel renders its subscriber and video counts alongside the URL rather than the link alone. The attributes were already present on theoutput_format: "json"form; this surfaces them in the default markdown.
Agent discovery (auth.md)
/auth.md— both hosts now serve the auth.md agent-onboarding document athttps://api.particle.pro/auth.mdandhttps://mcp.particle.pro/auth.md: the discovery walkthrough, a credential decision tree, registration steps, errors, and revocation, with the flows Particle Pro deliberately does not offer declared up front.agent_authblock — the AS metadata now embeds a machine-readable registration summary (register_uri, identity and credential types, revocation). Authentication → Agent discovery.- REST protected-resource metadata —
https://api.particle.pro/.well-known/oauth-protected-resourcenow serves an RFC 9728 document describing the REST API resource (previously 404). The MCP document athttps://mcp.particle.pro/.well-known/oauth-protected-resourceis unchanged.
Skill bundles and exact-tool selection
- Skill bundles — three ready-made skills (Podcast Intelligence, Company Deep Dive, Guest & People Research): a connection URL scoped to just the tools each workflow needs, plus a copy-paste SKILL.md that teaches your agent the workflow.
?tools=selector — pin a connection to exactly the tools you want advertised:?tools=particle_podcast_resolve,particle_podcast_search_transcripts. See Tool sets & discovery.- More clients in the quickstart — Windsurf, Zed, ChatGPT developer mode, and server-side wiring examples for the Anthropic Messages API and OpenAI Responses API. Quickstart.
Connect without a browser
- API keys as MCP credentials — the server now accepts the same
pp_*project API keys as the REST API (Authorization: BearerorX-API-Key), so headless agents — cron jobs, the OpenAI Responses API, server-side harnesses — no longer need an interactive OAuth consent. OAuth remains the recommended path when a human is present. Authentication. - One-click installs — Cursor and VS Code install buttons in the Quickstart.
- llms.txt — now opens with instructions for LLM agents: which surface to pick, how the tools compose, and the conventions that save wasted round-trips.
Smarter discovery on connect
- Conventions taught up front — connecting clients now receive server instructions covering the two things a bare tool list doesn’t show: tools are lean by default and expand via
include/mode/formatparameters, and every slug a tool returns is a valid input to the other tools (resolve a name once, then traverse). particle_catalogshows each tool’s depth — the catalog menu lists every tool’s expand options (↳ include: … · mode: …), so an agent can see what a tool can really do before fetching its full schema.
25 tools, flat names, opt-in categories
- Renames (action needed if you call tools by name) — every tool moved to a flat
particle_*identifier, e.g.entities/resolve_entity→particle_entity_resolve. The tool reference lists all current names. - Consolidations —
search_dialogueandlist_clipsmerged intoparticle_podcast_search_transcripts: relevant clips now arrive inline on search matches, and a known episode’s full clip list comes fromparticle_podcast_get_episodewithinclude: ["clips"].get_entity_mentionsbecameparticle_podcast_find_mentions. Boolean flags on get-tools becameincludearrays. - 12 new tools — people profiles and resolution, podcast guests, chart rankings, publishers, listener ratings, and political-bias and brand-suitability analytics. Browse them in the tool reference.
- Default vs opt-in advertisement — six tool categories advertise on a bare connection; five more (advertising, publishers, ratings, bias, suitability) advertise when you opt in with
?include=. Every public tool stays callable by name either way, and the always-onparticle_catalog/particle_callmeta-tools let any connection discover and reach the full surface. Tool sets & discovery.
May 2026
Launch
- The Particle Pro MCP server ships at
https://mcp.particle.pro: read-only tools over podcasts, companies, and the knowledge graph, with OAuth 2.1 and markdown outputs designed for agent loops. - MCP requests and per-tool usage appear in your organization’s request logs alongside REST traffic.
Missing something? Email api@particle.pro.