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

# Changelog

> What's new on the Particle Pro REST API — new endpoints and capabilities, and anything that could affect an existing integration.

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.

## July 2026

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

A new [`POST /v1/alerts/{id}/test-webhook`](/api-reference/alerts/send-a-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](/alerts/webhooks#send-a-test-event).

## June 2026

### Alert filters — narrow what an alert surfaces

[`POST /v1/projects/{projectId}/alerts`](/api-reference/alerts/create-an-alert) and [`PATCH /v1/alerts/{id}`](/api-reference/alerts/update-an-alert) 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.
* **`relevance`** — `EVERYTHING` (default) returns on-target and incidental matches; `RELEVANT` narrows to on-target only, dropping passing mentions.
* **`source_popularity`** — `ANY` (default) keeps every match; `POPULAR` keeps only matches from the top 5% of currently-charting podcasts.
* **`speaker_roles`** — `PODCAST_SPEAKER` alerts only. Replaces the default appearance set (`GUEST`, `PANELIST`, `CORRESPONDENT`, `AUDIENCE`, `SOUNDBITE_SPEAKER` — `HOST` 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](/alerts/overview#filtering-matches) for the full spec and examples.

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

A new [`GET /v1/entities/search`](/api-reference/entities/search-entities) 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](/podcasts/search).

* **If you used it to search episode dialogue** (`semantic_search` / `keyword_search`), migrate to [`GET /v1/podcasts/episodes/search`](/podcasts/episode-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](mailto:api@particle.pro).
