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

# Person Discovery Watcher

> Turn a person search filter into a recurring feed. A Person Discovery Watcher re-runs your filters on a schedule and pushes new matching people to a webhook or Slack. Includes copy-paste curl recipes for personas, seniority, company size, tenure, and movement signals.

A **Person Discovery Watcher** turns a [Person Search](/person-docs/search/introduction) filter into a continuous feed. Each run re-evaluates your filters and delivers only the **new** matches to your channel — webhook or Slack. You get a deduplicated stream of people entering your criteria, without re-running searches yourself.

```
POST https://api.crustdata.com/watch/person/search
```

<Callout icon="coins" color="#5345e4">
  <strong>Pricing:</strong> the first run is a free baseline (up to 5 matches),
  then <code>0.5 credits per new person</code> delivered.
</Callout>

## Discovery vs. Entity watchers

A **Discovery Watcher** finds people you don't know yet — it re-runs a *filter* and surfaces whoever newly matches. Use it to build a feed of candidates or decision-makers entering your ICP.

An **Entity Watcher** tracks a *known list* of people and alerts you when their profiles change — a new job, a title bump, a location move. If you already hold the profile URLs, see [Entity Watchers](/watcher-docs/person/entity).

## How it runs

<Steps>
  <Step title="Create the watch">
    `POST` your `filters`, a `config` (schedule + result cap), and one or more
    `notifications` channels. The response returns a watch `id`.
  </Step>

  <Step title="Baseline run (free)">
    Within seconds, the first run delivers a **free baseline sample of up to 5
    matches** so you can confirm the setup and payload shape. No credits are charged.
  </Step>

  <Step title="Recurring runs">
    On your schedule (`every_hours`), the watcher re-runs your filters and delivers
    people **new or refreshed since the previous run**, up to `max_results_per_run`.
    You're charged per delivered person.
  </Step>
</Steps>

<Note>
  Each run delivers matches whose profile was **added or updated since the last
  run** — a feed of *movement* within your filter set, not a one-time export. To
  pull the full current match set, use [Person Search](/person-docs/search/introduction).
</Note>

## Request body

| Field                        | Required | Description                                                                                                                                          |
| ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `filters`                    | Yes      | A filter tree, identical to [Person Search](/person-docs/search/reference). `{ "op": "and"\|"or", "conditions": [ { "field", "type", "value" } ] }`. |
| `config.trigger`             | Yes      | `{ "type": "interval", "every_hours": N }` — how often the watch runs (e.g. `1`, `6`, `24`, `168`).                                                  |
| `config.max_results_per_run` | No       | Max records delivered per run. Default `25`. The first (baseline) run is always capped at 5.                                                         |
| `config.expires_at`          | No       | ISO date (`"2027-01-01"`). The watch auto-stops after this date.                                                                                     |
| `notifications`              | Yes      | One or more delivery channels (see [below](#delivery-channels)).                                                                                     |

The response returns the watch `id`:

```json theme={"theme":"vitesse-black"}
{ "id": 46849 }
```

<Note>
  All examples require the headers `authorization: Bearer YOUR_API_KEY`,
  `content-type: application/json`, and `x-api-version: 2025-11-01`. For the
  full list of `field` values and operators, see the
  [Person Search reference](/person-docs/search/reference).
</Note>

## Filter format

Watcher filters use the **same syntax and fields** as [Person Search](/person-docs/search/reference) — no new filter language to learn. Every filter is a tree:

```json theme={"theme":"vitesse-black"}
{
  "op": "and",
  "conditions": [
    { "field": "experience.employment_details.current.title", "type": "(.)", "value": "Head of Data" },
    { "field": "professional_network.location.raw", "type": "(.)", "value": "United States" }
  ]
}
```

Each leaf is a `{ field, type, value }` triple: `field` is the attribute, `type` is the operator (`(.)` for contains, `=`, `in`, `not_in`, `=>` for ≥, `=<` for ≤, and so on), and `value` is what to match. Each `op` combines its `conditions` with `and` or `or`, and op-groups nest — put an `and` group inside an `or` group's `conditions` for "A **and** B, **or** C". See the [Person Search reference](/person-docs/search/reference) for the full field and operator catalog.

## Recipes

### Persona: title + location

Alert daily when new **ML engineers in Paris** appear:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        { "field": "experience.employment_details.current.title", "type": "(.)", "value": "Machine Learning Engineer" },
        { "field": "professional_network.location.raw", "type": "(.)", "value": "Paris" }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 }, "max_results_per_run": 25 },
    "notifications": [ { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" } ]
  }'
```

### Persona at a company-size band

New **VPs of Finance at 51–500-employee companies**:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        { "field": "experience.employment_details.current.title", "type": "in", "value": ["Chief Financial Officer", "VP Finance", "Vice President Finance"] },
        { "field": "experience.employment_details.current.company_headcount_latest", "type": "=>", "value": 51 },
        { "field": "experience.employment_details.current.company_headcount_latest", "type": "=<", "value": 500 }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 } },
    "notifications": [ { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" } ]
  }'
```

### Seniority + skills

New **CXO-level people with machine-learning skills**:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        { "field": "experience.employment_details.current.seniority_level", "type": "=", "value": "CXO" },
        { "field": "skills.professional_network_skills", "type": "(.)", "value": "machine learning" }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 } },
    "notifications": [ { "type": "slack", "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX" } ]
  }'
```

### Movement signal: recently changed jobs

People who **recently changed jobs** (a new decision-maker signal — best for sales/GTM):

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        { "field": "experience.employment_details.current.title", "type": "(.)", "value": "VP of Sales" },
        { "field": "recently_changed_jobs", "type": "=", "value": true }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 } },
    "notifications": [ { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" } ]
  }'
```

### Education filter, excluding companies

Stanford alumni who are **not** currently at the big three:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/person/search \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --header 'x-api-version: 2025-11-01' \
  --data '{
    "filters": {
      "op": "and",
      "conditions": [
        { "field": "education.schools.school", "type": "(.)", "value": "Stanford" },
        { "field": "experience.employment_details.current.company_name", "type": "not_in", "value": ["Google", "Meta", "Amazon"] }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 168 } },
    "notifications": [ { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" } ]
  }'
```

## Delivery channels

Every watch needs at least one channel in `notifications`. Add one or more; matches fan out to all of them.

<CodeGroup>
  ```json Webhook theme={"theme":"vitesse-black"}
  { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata", "headers": { "X-Watch-Name": "ml-engineers-paris" } }
  ```

  ```json Slack theme={"theme":"vitesse-black"}
  { "type": "slack", "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX" }
  ```

  ```json Multiple theme={"theme":"vitesse-black"}
  [
    { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" },
    { "type": "slack", "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX" }
  ]
  ```
</CodeGroup>

<Warning>
  A Slack channel must be a genuine Slack incoming webhook
  (`https://hooks.slack.com/services/…`). Any other URL will fail delivery.
</Warning>

## Manage a watch

<CodeGroup>
  ```bash List runs theme={"theme":"vitesse-black"}
  curl --request GET \
    --url 'https://api.crustdata.com/watcher/watches/46849/runs?limit=20' \
    --header 'authorization: Bearer YOUR_API_KEY'
  ```

  ```bash Run detail (delivered records) theme={"theme":"vitesse-black"}
  curl --request GET \
    --url https://api.crustdata.com/watcher/watches/46849/runs/54811/summary \
    --header 'authorization: Bearer YOUR_API_KEY'
  ```

  ```bash Cancel a watch theme={"theme":"vitesse-black"}
  curl --request DELETE \
    --url https://api.crustdata.com/watcher/watches/46849 \
    --header 'authorization: Bearer YOUR_API_KEY'
  ```
</CodeGroup>

## Pricing

|                                         | Credits  |
| --------------------------------------- | -------- |
| First run (baseline, up to 5 matches)   | **Free** |
| Each new person delivered on later runs | **0.5**  |

You're charged only for records actually delivered — never for a run that finds nothing new. For the full credit catalog, see [Pricing](/general/pricing).

## Related

<CardGroup cols={2}>
  <Card title="Entity watchers" icon="clock" href="/watcher-docs/person/entity">
    Watch a known list of people for profile changes.
  </Card>

  <Card title="Person Search" icon="user" href="/person-docs/search/introduction">
    Run the underlying search on demand and pull the full current match set.
  </Card>

  <Card title="Person Search reference" icon="book" href="/person-docs/search/reference">
    The complete catalog of filter fields and operators.
  </Card>

  <Card title="Pricing" icon="coins" href="/general/pricing">
    Credit costs across every Crustdata endpoint.
  </Card>
</CardGroup>
