# Webhooks, duplicates & cancelling

> A webhook per alert, retried next run if it fails, de-duplicated by alert id on your side, and a monitor you cancel when the person leaves.

- **HTML:** https://offendersearch.app/docs/guides/monitoring/webhooks-and-lifecycle
- **Base URL (live):** https://api.offendersearch.app — live keys (`os_live_…`)
- **Base URL (sandbox):** https://sandbox.offendersearch.app — test keys (`os_test_…`), never billed
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **Docs index for agents:** https://offendersearch.app/llms.txt

## Configuring a webhook

Set `channels.webhookUrl` when you create the monitor (`POST /v1/monitors`); email delivery is `channels.email`. The URL must be `https` on a public host. Put a secret token in the URL and verify it on receipt.

```json
{ "product": "sex-offender", "type": "person", "label": "Jordan Rivera — resident 48213",
  "person": { "firstName": "Jordan", "lastName": "Rivera", "dob": "1988-04-12" },
  "channels": { "webhookUrl": "https://example.com/hooks/offendersearch?token=YOUR_SECRET" } }
```

## Delivery and retries

- Monitors are evaluated once a day. Each alert is delivered once per channel: one `POST` with `type: "monitor.alert"` and the alert body.
- If neither email nor webhook succeeded, the alert stays pending and both are tried again on the next run, the following day. There is no faster retry schedule.
- Every delivery carries `X-Offendersearch-Signature: t=<unix>,v1=<hex>` — the HMAC-SHA256, with the monitor's `webhookSecret` (returned once on the `201`), of `<t>.<raw body>`. Verify it before acting (see [Delivery](/docs/monitoring/delivery)), and read the alert back from `GET /v1/monitors/{monitorId}/alerts` when you need certainty. [Delivery](/docs/monitoring/delivery) carries the current status.

## Duplicate alerts

- Key your processing on the alert's id; a redelivery after a failed run carries the same id.
- An alert names its event (`new`, `changed`, `removed`) and the record (`personRef`, and `externalId` for criminal records). The same record changing twice produces two alerts with different ids.
- Alert history is the source of truth: `GET /v1/monitors/{monitorId}/alerts` returns every alert whatever happened to its delivery (newest first, up to 200).

## Cancelling

`DELETE /v1/monitors/{monitorId}` cancels a monitor: evaluation stops now and it is not charged on any invoice prepared after the cancel (monitors are billed flat per active monitor, $3 person or $10 location, counted at invoice time; there is no proration). Its alerts stay readable. Cancelling twice is harmless. See [Billing](/docs/monitoring/billing).

## Related

- [Delivery](https://offendersearch.app/docs/monitoring/delivery)
- [Alerts](https://offendersearch.app/docs/monitoring/alerts)
- [Monitoring API reference](https://offendersearch.app/docs/monitoring/api-reference)
