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

# Watch datasets

> Have Ploti tell your assistant or agent when a dataset gets a new version or a request moves, then read exactly the rows that changed. Notify only, on any plan.

An assistant or agent doesn't have to keep checking Ploti to learn that something changed. It can watch a dataset, one table of official records such as a county's building permits. Each time the dataset gets a new version, Ploti calls a web address of yours with what changed. Your agent then reads only the rows that were added, changed or removed, such as the new permits someone is waiting for, and acts on them.

Watching only notifies. It keeps no copy of the data for you, and it works on any Ploti plan.

To keep a full copy of a dataset in your own system instead, use [Data Feeds](https://ploti.ai/docs/feeds/overview.md), which has [its own events](https://ploti.ai/docs/feeds/events.md).

## Webhooks

A **webhook** is an https address you control. Ploti sends it a signed POST for each event, the moment it happens.

* `webhooks create` takes the address and an optional description. It returns a **signing secret** once. Keep it with your receiver.
* Over the REST API or the CLI, it also takes an optional header your receiver requires, such as a bearer key. Ploti sends it with every POST and never shows it again. An assistant cannot set one.
* `webhooks list`, `webhooks test` (sends a signed `ping`) and `webhooks delete` manage them.

A member may have 20 webhooks, and each belongs to the member whose key made it.

Each POST is JSON `{id, type, timestamp, data}`, the same shape for every event. Answer `2xx` quickly and do the work afterwards. A failed delivery is retried six times, at growing intervals, over about a day and a half.

A webhook made for a [Data Feeds subscription](https://ploti.ai/docs/feeds/events.md#webhooks-for-a-subscription) receives only that subscription's feed events. Every other webhook receives these three kinds of event:

| Events | Sent when |
| - | - |
| `dataset.changed` | A dataset you watch has a new version |
| `research_request.*`, `data_request.*` | A [research request](https://ploti.ai/docs/research/overview.md) or the data it asked for moves, or Ploti needs your answer |
| `ping` | You ran `webhooks test` |

## Watch a dataset

`datasets watch` takes a dataset id. From then on, each new version sends a `dataset.changed` event to all your webhooks. `datasets unwatch` stops it, and `datasets watches` lists what you watch. Watching a dataset twice changes nothing.

A member may watch 100 datasets. Any kind of dataset can be watched, documents included, as long as your workspace's coverage and plan open it.

```json theme={null}
{
  "id": "...",
  "type": "dataset.changed",
  "timestamp": "...",
  "data": {
    "id": "ds_orange_fl_building_permits",
    "title": "Building permits",
    "place": "Orange County",
    "version": 118,
    "promotedAt": "...",
    "summary": "...",
    "counts": { "added": 212, "changed": 38, "removed": 3 },
    "changeLog": "recorded",
    "provenanceUrl": "..."
  }
}
```

* `data.version` is the new version: Ploti's own number for the dataset's published data, separate from Data Feeds version numbers.
* `data.promotedAt` is when it went live.
* `data.counts` is what it added, changed and removed.
* `data.provenanceUrl` says where its values come from.

## Read what changed

`datasets changes` with the event's version lists exactly the rows it added, changed, removed or renamed (a record that now carries a new id). The added and changed rows of the latest version come with the row itself.

`changeLog` says what was recorded for the version:

* `recorded`: every changed row is listed.
* `counts_only`: only the totals were kept. Read the dataset with your own conditions instead.
* `ids_changed`, `full_refresh` or `first`: the dataset's ids were replaced, it was reloaded whole, or this is its first version, so there is no row-by-row list. Read it again with `datasets_rows`.

## Verify each delivery

Check the signature before acting on a POST. Ploti signs with [Standard Webhooks](https://www.standardwebhooks.com), whose libraries do this for most languages:

* `webhook-id`: the delivery's id, the same on each retry. To skip an event you've already handled, check the `id` in the body.
* `webhook-timestamp`: Unix seconds when it was signed. Reject one more than 5 minutes old.
* `webhook-signature`: `v1,<base64>`, an HMAC-SHA256 of `<webhook-id>.<webhook-timestamp>.<raw body>` keyed with the base64 bytes after `whsec_` in the secret. Compare in constant time. While a secret rotates, several signatures are sent, separated by spaces, and any one matching is enough.

## Request events

* `data_request.sourcing`, `.matched`, `.checkpoint_released` (the first results arrived), `.ready`, `.failed`, `.cancelled`, `.paid_source`, `.cycle_refused`, `.question` (Ploti needs the member's answer, given in Ploti) and `.question_reminder`.
* `research_request.report_ready` (Ploti's check reported what data exists and what is missing), `.question` (the check needs the member's answer; `data.questions` has the questions, and `requests questions answer` sends the answers), `.answered` (`data.answer`) and `.needs_attention` (the research can't finish on its own).

`data.url` on a request event opens the request in Ploti.

```json MCP theme={null}
{
  "tool": "datasets_watch",
  "arguments": { "dataset": "ds_orange_fl_building_permits" }
}
```

```bash CLI theme={null}
ploti webhooks create https://example.com/hooks/ploti --description "New permits"
ploti datasets watch ds_orange_fl_building_permits
ploti datasets changes ds_orange_fl_building_permits --version 118
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.