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

# Monitors

> Watch a dataset endpoint on a schedule and get what is new by email: how monitors run after each source refresh, what they charge, the relevance filter, and the full API.

A **monitor** is a saved query on one dataset endpoint that Croma evaluates on
a schedule and emails to up to three addresses. You describe what to watch the
same way you would query the endpoint; Croma keeps the schedule, remembers what
it already reported, and sends only what appeared since the last run.

<Note>
  Monitors are a feature of the API. Create them with `POST /monitors`, by
  asking Claude or any MCP client ([Monitors from Claude](/monitors-mcp)) or
  from the console at
  [platform.usecroma.com/monitors](https://platform.usecroma.com/monitors).
  All three manage the same monitors.
</Note>

## Which endpoints can be monitored?

Every endpoint that answers from a Croma dataset and pages its results: see
[Monitorable sources](/monitors-sources) for the list, with each one's tool
name and refresh time. `GET /catalog` marks the same endpoints with
`monitorable: true`. Live lookups, which query the source at request time,
cannot be monitored yet.

## Create one

```bash theme={"dark"}
curl -X POST https://api.croma.run/monitors \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Contrato AD9-111",
    "endpoint": "/co/anm/notices-search/v1",
    "query": { "title_number": "AD9-111" },
    "schedule": { "cadence": "source" },
    "recipients": ["legal@example.com"],
    "notify": "always",
    "language": "es"
  }'
```

| Field        | Meaning                                                                                                                                 |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `endpoint`   | The endpoint to watch, by path, catalog id or MCP tool name (`anm_notices_search`).                                                     |
| `query`      | The request body the monitor sends on every run, validated exactly as a direct request would be. `page` and `per_page` are not allowed. |
| `schedule`   | When to run. See below. Default `{ "cadence": "source" }`.                                                                              |
| `recipients` | One to three email addresses.                                                                                                           |
| `notify`     | `always` (default) sends an email on every run, including one that found nothing new; `on_new` only when there is something to report.  |
| `language`   | `es` (default) or `en`, for the emails.                                                                                                 |
| `relevance`  | Optional. A plain-language instruction that filters new results before they are sent. See below.                                        |

The response is the monitor with its compiled schedule:

```json theme={"dark"}
{
  "data": {
    "id": "mon_5f1c2c0a-9d1e-4a3b-8c7d-1e2f3a4b5c6d",
    "name": "Contrato AD9-111",
    "endpoint": { "id": "anm-notices-search", "path": "/co/anm/notices-search/v1", "source": "ANM", "name": "Notices Search" },
    "query": { "title_number": "AD9-111" },
    "relevance": null,
    "schedule": { "cadence": "source", "timezone": "America/Bogota", "cron": "30 7 * * *", "next_run_at": "2026-09-22T12:30:00.000Z" },
    "recipients": ["legal@example.com"],
    "notify": "always",
    "language": "es",
    "status": "active",
    "created_at": "2026-09-21T15:04:05.000Z",
    "updated_at": "2026-09-21T15:04:05.000Z",
    "last_run": null
  }
}
```

## The first run

Right after creation the monitor runs once to record what already matches
today (up to 200 rows) and sends a welcome email with that count and the next
run time. From then on, every run reports only rows that were not seen before.

## Schedules

| `cadence` | Runs                                                                                                                    |
| --------- | ----------------------------------------------------------------------------------------------------------------------- |
| `source`  | Right after the dataset's own refresh completes. For a daily source that is once a day, as soon as new data has landed. |
| `hourly`  | Every hour, on the hour.                                                                                                |
| `daily`   | Every day at `at` (HH:MM, default 08:00) in `timezone` (default the dataset's).                                         |
| `weekly`  | Every `weekday` (default monday) at `at`.                                                                               |

A monitor can never check a source more often than the source refreshes: a
`daily` dataset refuses `hourly` with `schedule_faster_than_source`. When a
`source` run has to go ahead without the day's refresh (the source did not
publish), the run and its email say so: `source_stale` is `true` and the email
reads "the source has not published new data since…", never a plain "nothing
new".

## The relevance filter

With `relevance` set, every new row is judged against your instruction before
the email goes out. Rows the filter discards are never lost: they stay in the
monitor with `relevant: false` and the email says how many were left out. If
the filter is unavailable, the rows are sent flagged as unreviewed rather than
dropped.

```json theme={"dark"}
{ "relevance": "solo avisos sobre suspensión o caducidad del título" }
```

`GET /monitors/{id}/matches?relevant=false` lists what was discarded, with the
reason for each row.

## Manage it

| Call                         | What it does                                                                                         |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- |
| `GET /monitors`              | Your monitors, with each one's last run.                                                             |
| `GET /monitors/{id}`         | One monitor.                                                                                         |
| `PATCH /monitors/{id}`       | Change anything but the endpoint. `{ "status": "paused" }` pauses, `{ "status": "active" }` resumes. |
| `POST /monitors/{id}/run`    | Run now, outside the schedule.                                                                       |
| `GET /monitors/{id}/runs`    | Every run: when, what it found, whether the email went out.                                          |
| `GET /monitors/{id}/matches` | Every reported row, with the relevance verdict.                                                      |
| `DELETE /monitors/{id}`      | Removes the monitor, its schedule, runs and matches.                                                 |

Every email carries an unsubscribe link for its recipient. A monitor left with
no recipients is paused.

## Credits and limits

Each run spends the same credits as one request to the endpoint (a dataset
request). Creating and managing monitors is free. When the organization has
no credits left, the run is recorded as `skipped_plan_limit`, the recipients
are told once a day, and the schedule stays in place.

An organization can have up to 20 monitors, each with up to 3 recipients. A
run reports up to 500 new rows; beyond that it is flagged `truncated`.
