# Endpoint & error reference

> The five monitoring endpoints — create, list, retrieve, cancel and alert history — with request and response bodies, and the error envelope you switch on.

- **HTML:** https://offendersearch.app/docs/monitoring/endpoints
- **Base URL:** https://api.offendersearch.app
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **Monitoring reference as markdown:** https://offendersearch.app/docs/monitoring.md

## The five endpoints

Every request authenticates with the `X-API-Key` header. Base URL `https://api.offendersearch.app`.

| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/v1/monitors` | Create a monitor. Returns the monitor object. |
| `GET` | `/v1/monitors` | List this account’s monitors. |
| `GET` | `/v1/monitors/{id}` | Retrieve one monitor together with its recent alerts. |
| `DELETE` | `/v1/monitors/{id}` | Cancel a monitor. Stops billing at the period end (prorated). |
| `GET` | `/v1/monitors/{id}/alerts` | The full alert history for one monitor, most recent first. |

## POST /v1/monitors

Create a monitor. `product`, `type`, the matching predicate, and at least one channel are required.

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `product` | string | required | `sex-offender` or `criminal`. |
| `type` | string | required | `person` or `location`. |
| `person` | object | required for `person` | `{ firstName, lastName, dob }`. Send a `dob` — a name-only watch is noisy. |
| `location` | object | required for `location` | `{ address }` or `{ lat, lng }`, plus `radiusMiles`. |
| `minConfidence` | string | optional · default `dob_match` | The alert floor: `dob_match` or `year_match`. |
| `label` | string | optional | Your own label for the monitor. |
| `channels` | object | required | `{ email?, webhookUrl? }` — at least one. |

```bash
curl -X POST "https://api.offendersearch.app/v1/monitors" \
  -H "X-API-Key: $OFFENDERSEARCH_KEY" -H "Content-Type: application/json" \
  -d '{ "product": "sex-offender", "type": "person",
        "person": { "firstName": "Jordan", "lastName": "Rivera", "dob": "1988-04-12" },
        "channels": { "email": "alerts@example.com" } }'
```

> A `POST` for `product: "criminal"` with `type: "location"` returns a `200` with `status: "not_yet_available"` — no monitor is created and nothing is billed. See [Location monitoring](https://offendersearch.app/docs/monitoring/location-monitoring.md).

## GET /v1/monitors

List every monitor on the account, active and cancelled.

```json
{
  "monitors": [
    { "id": "mon_7f2a1c9e0b4d", "product": "sex-offender", "type": "person",
      "status": "active", "label": "Jordan Rivera — SO watch",
      "createdAt": "2026-09-05T14:02:11+00:00" }
  ],
  "count": 1
}
```

## GET /v1/monitors/{id} and /alerts

Retrieve one monitor with its recent alerts, or its full alert history. Both are scoped to the creating account; another account’s `id` returns `404`. Full shapes are on [The Monitor object](https://offendersearch.app/docs/monitoring/monitor-object.md) and [Alerts](https://offendersearch.app/docs/monitoring/alerts.md).

## DELETE /v1/monitors/{id}

Cancel a monitor. Returns the monitor with `status: "canceled"`; billing stops at the period end (prorated). The monitor stays readable so its alert history is preserved.

```json
{ "id": "mon_7f2a1c9e0b4d", "status": "canceled",
  "canceledAt": "2026-09-20T18:30:00+00:00",
  "billedThrough": "2026-10-05T00:00:00+00:00" }
```

## The error envelope

Errors are returned as a single, consistent nested object across every endpoint — the same shape as the other products. `code` is a **stable machine token**; `message` is human-readable and may be reworded. **Branch on `code`, render `message`.**

```json
{ "error": { "code": "monitor_missing_channel",
             "message": "a monitor needs at least one channel — set channels.email or channels.webhookUrl" } }
```

| HTTP | `code` | When you will see it |
| --- | --- | --- |
| `200` | — | A monitor was created, listed, retrieved or cancelled — or a coming-soon combination returned `not_yet_available`. |
| `400` | `monitor_missing_predicate` | A `person` monitor with no `person`, or a `location` monitor with no `location`. |
| `400` | `monitor_missing_channel` | No `channels.email` and no `channels.webhookUrl`. |
| `400` | `invalid_product` / `invalid_type` | A `product` other than `sex-offender`/`criminal`, or a `type` other than `person`/`location`. |
| `401` | `unauthenticated` | The `X-API-Key` header is missing or malformed. |
| `404` | `not_found` | No monitor carries the id you asked for, or it belongs to another account. |

> **There is no request rate limit today** — no endpoint returns `429`. Apply your own client-side concurrency control.

> The Monitoring API is not a consumer reporting agency and its alerts are not a consumer report. The notice — *Not a consumer report. This information may not be used for any purpose under the Fair Credit Reporting Act (15 U.S.C. § 1681 et seq.).* — accompanies every monitor and every alert.

---

## Related

- Previous: [Billing — one predicate, one charge](https://offendersearch.app/docs/monitoring/billing.md)
- Index: [Monitoring API reference](https://offendersearch.app/docs/monitoring.md)
