> ## 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.

# Job Watcher

> Turn a job search filter into a recurring feed. A Job Watcher re-runs your filters on a schedule and pushes newly posted jobs to a webhook, Slack, or email. Includes copy-paste curl recipes for titles, locations, company size, and posting recency.

A **Job Watcher** turns a [Job Search](/job-docs/search/introduction) filter into a continuous feed. Each run re-evaluates your filters and delivers only the **new** matching jobs to your channel, so you get a deduplicated stream of postings entering your criteria without re-running searches yourself.

```
POST https://api.crustdata.com/watch/job/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 job</code> delivered.
</Callout>

## 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
    jobs **new since the previous run**, up to `max_results_per_run`. You're charged
    per delivered job.
  </Step>
</Steps>

<Note>
  Bound your filter by posting date. A leaf like
  `{ "field": "metadata.date_added", "type": "=>", "value": "2026-07-05" }`
  keeps the watch focused on fresh postings instead of the full historical
  pool. Thirty days back is a good default.
</Note>

## Request body

| Field                        | Required | Description                                                                                                                                    |
| ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `filters`                    | Yes      | A filter tree, identical to [Job Search](/job-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 jobs 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.                                                                               |
| `sorts`                      | No       | Delivery order, e.g. `[ { "field": "metadata.date_added", "order": "desc" } ]` for newest first.                                               |
| `notifications`              | Yes      | One or more delivery channels (see [below](#delivery-channels)).                                                                               |

The response returns the watch `id`:

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

<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
  [Job Search reference](/job-docs/search/reference).
</Note>

## Filter format

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

```json theme={"theme":"vitesse-black"}
{
  "op": "and",
  "conditions": [
    { "field": "job_details.title", "type": "(.)", "value": "software engineer" },
    { "field": "location.country", "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.

## Recipes

### Title + location + company size

Alert daily on new **software engineer roles in the United States at 3,000+ person companies**, newest first:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/job/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": "job_details.title", "type": "(.)", "value": "software engineer" },
        { "field": "location.country", "type": "=", "value": "United States" },
        { "field": "company.headcount.total", "type": "=>", "value": 3000 }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 }, "max_results_per_run": 25 },
    "sorts": [ { "field": "metadata.date_added", "order": "desc" } ],
    "notifications": [ { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" } ]
  }'
```

### Recent postings in a category

New **engineering roles posted in the last 30 days**, at companies that raised a round:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/job/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": "job_details.category", "type": "=", "value": "Engineering" },
        { "field": "metadata.date_added", "type": "=>", "value": "2026-07-05" },
        { "field": "company.funding.last_round_type", "type": "in", "value": ["Series A", "Series B"] }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 24 } },
    "notifications": [ { "type": "slack", "webhook_url": "https://hooks.slack.com/services/T000/B000/XXXX" } ]
  }'
```

### Remote roles at specific companies

New **remote postings** from a set of companies you track:

```bash theme={"theme":"vitesse-black"}
curl --request POST \
  --url https://api.crustdata.com/watch/job/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": "company.basic_info.primary_domain", "type": "in", "value": ["stripe.com", "figma.com"] },
        { "field": "job_details.workplace_type", "type": "=", "value": "Remote" }
      ]
    },
    "config": { "trigger": { "type": "interval", "every_hours": 6 } },
    "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": "swe-us-3000" } }
  ```

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

  ```json Email theme={"theme":"vitesse-black"}
  { "type": "email", "to": ["you@company.com"] }
  ```

  ```json Multiple theme={"theme":"vitesse-black"}
  [
    { "type": "webhook", "url": "https://your-app.com/webhooks/crustdata" },
    { "type": "email", "to": ["you@company.com"] }
  ]
  ```
</CodeGroup>

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

## Delivered record shape

Each delivered job carries the posting, the company, and the location:

```json theme={"theme":"vitesse-black"}
{
  "uid": "indb_discovery_job_58504943",
  "record": {
    "job_details": {
      "title": "Backend Engineer, Vehicle Software",
      "url": "https://www.linkedin.com/jobs/view/4448814407",
      "category": "Engineering",
      "workplace_type": "On-site",
      "number_of_openings": 1
    },
    "company": { "basic_info": { "name": "Tesla", "primary_domain": "tesla.com" } },
    "location": { "raw": "Palo Alto, California, United States", "country": "United States" },
    "metadata": { "date_added": "2026-08-04T05:32:47" }
  }
}
```

## Manage a watch

<CodeGroup>
  ```bash Pause / resume theme={"theme":"vitesse-black"}
  curl --request PATCH \
    --url https://api.crustdata.com/watch/job/search/47609 \
    --header 'authorization: Bearer YOUR_API_KEY' \
    --header 'content-type: application/json' \
    --header 'x-api-version: 2025-11-01' \
    --data '{ "status": "paused" }'
  ```

  ```bash Cancel a watch theme={"theme":"vitesse-black"}
  curl --request DELETE \
    --url https://api.crustdata.com/watch/job/search/47609 \
    --header 'authorization: Bearer YOUR_API_KEY' \
    --header 'x-api-version: 2025-11-01'
  ```

  ```bash List your job watches theme={"theme":"vitesse-black"}
  curl --request GET \
    --url https://api.crustdata.com/watch/job/search \
    --header 'authorization: Bearer YOUR_API_KEY' \
    --header 'x-api-version: 2025-11-01'
  ```
</CodeGroup>

## Pricing

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

You're charged only for jobs 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="Job Search" icon="briefcase" href="/job-docs/search/introduction">
    Run the underlying search on demand and pull the full current match set.
  </Card>

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

  <Card title="Person watchers" icon="user" href="/watcher-docs/person/discovery">
    The same recurring-feed model over people.
  </Card>

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


## Related topics

- [Person Discovery Watcher](/watcher-docs/person/discovery.md)
- [Person Entity Watcher](/watcher-docs/person/entity.md)
- [Company Entity Watcher](/watcher-docs/company/entity.md)
- [Company Discovery Watcher](/watcher-docs/company/discovery.md)
- [Pricing](/general/pricing.md)
