Alerts, events & cadence
The alert object, the new / changed / removed events, the daily cadence, and de-duplication.
Livehttps://api.offendersearch.appSandboxhttps://sandbox.offendersearch.appThe alert object
One person's latest event on one monitor, as the alert history and recentAlerts return it. There is one alert per monitor and person per registry: when a matched person's record changes again, or a registry republishes it under a new number, the alert keeps the same id and (on a change) takes the new eventType.
Returned or accepted by POST /v1/monitors, GET /v1/monitors, GET /v1/monitors/{monitorId}, GET /v1/monitors/{monitorId}/alerts.
| Field | Type | Description |
|---|---|---|
| id | string | The alert id: hit_ followed by 16 hex characters. Stable for one monitor and one person in one registry across events, including a registry renumbering the listing. A webhook delivery carries it as alertId.Example "hit_7fa176c8889c7569" |
| eventType | string one of "new", "changed", "removed" | The latest event for this person: new (the person newly matches), changed (a fact about them changed while matching — an address, an offense field, a status, a new booking), removed (they no longer match — no longer listed in that registry, or outside a location monitor's radius). A registry renumbering a listing is not an event. |
| matchLabel | string or null one of "dob_match", "year_match", "age_match", "name_match", "in_radius" | How the record matched: dob_match, year_match, age_match or name_match on a person monitor, in_radius on a location monitor. null on a removed event. |
| record | AlertRecord | The matched record, summarised. |
| firstSeenAt | string (date-time) | When this record first matched the monitor. Example "2026-09-06T12:00:41+00:00" |
| occurredAt | string (date-time) | The most recent evaluation that recorded this record for the monitor. Alerts are listed by this field, newest first. Example "2026-09-06T12:00:41+00:00" |
| notifiedAt | string (date-time) or null | When the current event was delivered by email or webhook; null until it has been. |
{
"id": "hit_7fa176c8889c7569",
"eventType": "new",
"matchLabel": "dob_match",
"record": {
"name": "JORDAN RIVERA",
"jurisdiction": "TX",
"locality": "Houston",
"matchLabel": "dob_match",
"matchConfidence": 1.0,
"personRef": "prs_3c9e1f0a7b2d4e6f8a1b",
"recordId": "rec_ab12cd34ef56gh78ij90"
},
"firstSeenAt": "2026-09-06T12:00:41+00:00",
"occurredAt": "2026-09-06T12:00:41+00:00",
"notifiedAt": "2026-09-06T12:01:03+00:00"
}{
"id": "hit_5f91357bf82b5637",
"eventType": "removed",
"matchLabel": null,
"record": { "event": "removed", "jurisdiction": "TX" },
"firstSeenAt": "2026-08-02T12:00:37+00:00",
"occurredAt": "2026-09-14T12:00:52+00:00",
"notifiedAt": null
}The AlertRecord object — the matched record in an alert
The matched record, summarised: record on an alert, detail on a webhook delivery. It names the person and a city, never a street address, and carries the personRef to recognise the person by. On a removed event it carries event and jurisdiction; reconcile a removal by the alert's id, which does not change. Run a search with the monitor's criteria, or fetch recordId, for the full record.
Returned or accepted by POST /v1/monitors, GET /v1/monitors, GET /v1/monitors/{monitorId}, GET /v1/monitors/{monitorId}/alerts.
| Field | Type | Description |
|---|---|---|
| name | string | The person's full name as the record publishes it. Absent on a removed event.Example "JORDAN RIVERA" |
| jurisdiction | string | The two-letter code of the publishing jurisdiction (on a criminal record, its state or county code). Example "TX" |
| locality | string | The record's residence city (or its first address city), never a street. "" when the record publishes no city. Absent on a removed event.Example "Houston" |
| matchLabel | string one of "dob_match", "year_match", "age_match", "name_match", "in_radius" | How the record matched — the same value as the alert's matchLabel. Absent on a removed event. |
| matchConfidence | number or null | The record's match confidence from 0 to 1, or null when it was not scored. Absent on a removed event.Example 1 |
| personRef | string or null | The person this alert is about, within the publishing registry or source — the same personRef the matching record carries in search results. It does not change when a registry republishes the listing under a new number, so de-duplicate and reconcile on it. null when the record carries none. Present on removed records too, so a removal can be matched to the person.Example "prs_3c9e1f0a7b2d4e6f8a1b" |
| recordId | string or null | On a sex-offender monitor, the recordId of the matching record at the time of the event, for GET /v1/records/{recordId}. null on a criminal monitor.Example "rec_ab12cd34ef56gh78ij90" |
| externalId | string or null | The record's own id at its source. Set for criminal records (the same externalId the Criminal Records API returns); null for registry records. |
| recordType | string or null | Criminal monitors: the matched record's recordType — court_case, doc_inmate, jail_booking, healthcare_exclusion and the other values the criminal record carries. null when the record names none; absent on a sex-offender monitor and on a removed event.Example "healthcare_exclusion" |
| exclusion | object | Present only when recordType is healthcare_exclusion: the exclusion list's own facts, so the alert can say "added to an exclusion list, authority 1128(a)(1)". On these records the event reads as added to (new), updated on (changed) or removed from (removed) an exclusion list. |
| exclusion.authority | string | The authority as the exclusion list labels it. Example "1128(a)(1)" |
| exclusion.convictionBased | boolean | Whether the basis is a criminal conviction. Only conviction-based exclusions alert. |
| exclusion.excludedOn | string or null | ISO date the exclusion took effect. Example "2021-03-19" |
| event | string one of "removed" | Present only on a removed event, always "removed". |
The three event types
| eventType | Meaning |
|---|---|
new | A person newly matches — someone who was not matching at the previous evaluation. On a location monitor, a match moved into the radius. The first evaluation after you create a monitor reports everyone who already matches as new. |
changed | A fact about a person you are already matching changed — an address, an offense field, a status, or, on a criminal monitor, a new booking. A registry republishing the listing under a new number is not a change. |
removed | A person who was matching no longer matches — they are no longer listed in that registry, or, on a location monitor, they moved out of the radius. Disappearance is data, so it is reported. |
Exclusion-list alerts on a criminal monitor
A criminal person monitor also watches the exclusion-list records the criminal search carries — the HHS-OIG, SAM.gov and state Medicaid exclusion lists. Nothing changes on the request. On a criminal monitor record.recordType names the kind of record that matched, and when it is healthcare_exclusion the alert carries record.exclusion with the list’s authority, convictionBased and excludedOn. The event reads accordingly: new is a person added to an exclusion list, changed an exclusion updated on the list (a waiver or reinstatement date added, an authority corrected), and removed a person removed from the list — reinstated, or the exclusion term ended.
Only conviction-based exclusions alert, matching what a default search returns; administrative exclusions (license actions, debarments, loan defaults) never produce an alert. Because a person monitor is keyed on a date of birth, list entries that publish none — most SAM.gov and state entries — do not alert either.
{
"id": "hit_2c84e1f09a6b7d31",
"eventType": "new",
"matchLabel": "dob_match",
"record": {
"name": "ALEX Q HAMILTON",
"jurisdiction": "OH",
"locality": "Columbus",
"matchLabel": "dob_match",
"matchConfidence": 0.99,
"personRef": "prs_6d0c2a9e4b1f7e3a8c5d",
"recordId": null,
"recordType": "healthcare_exclusion",
"exclusion": { "authority": "1128(a)(1)", "convictionBased": true, "excludedOn": "2026-10-01" }
},
"firstSeenAt": "2026-10-11T06:00:12+00:00",
"occurredAt": "2026-10-11T06:00:12+00:00",
"notifiedAt": "2026-10-11T06:01:04+00:00"
}Cadence
Each monitor is evaluated once per day, against the continuously-updated dataset. An evaluation compares today’s matching records with the previous state and emits one alert per change. There is no faster tier and no way to force an off-cycle evaluation; a monitor is a daily watch by design.
One alert per person
A monitor keys its alerts on the person, not the listing. Within one registry — or, on a criminal monitor, one source — the person is identified by personRef, the same value the matching record carries in search results, and that value stays the same when the registry republishes the listing under a new number. The consequences:
- One thread per person per registry. Someone listed in two registries is two alerts, one per registry; someone whose listing a registry renumbered is still one alert, with the same
id. - A renumbered listing is not an event. It produces no
new, nochangedand noremoved.newmeans a person newly matches,changedmeans a fact about them changed, andremovedmeans they are no longer listed in that registry. - The alert carries the identifiers.
record.personRefis what to reconcile your own files on, withjurisdiction. On a sex-offender monitorrecord.recordIdis the matching record as it stood at the event, forGET /v1/records/{recordId}; read it as a pointer to that record, not as the person’s key.
De-duplication
A monitor keeps one alert per person per registry. A person who stays matched and unchanged is silent after their first new. When a fact about a matched person changes, or they stop matching, the same alert — same id — takes the new eventType (changed or removed), its notifiedAt resets to null, and the event is delivered again.
id as alertId, so de-duplicate deliveries on it and reconcile what your endpoint received against GET /v1/monitors/{id}/alerts, where every alert has a stable id and a notifiedAt. See Delivery.GET /v1/monitors/{id}/alerts — monitoring alert history API request and response fields
One monitor's alerts, most recently observed first — the system of record for every alert the monitor has raised, whether or not a delivery reached you.
Request
| Field | Type | Description |
|---|---|---|
| monitorId required | string | The monitor id (mon_…). Another account's monitor id is a 404.Example "mon_b8f40d7afb9dc0d8" |
| Field | Type | Description |
|---|---|---|
| limit optional · default 50 | integer | How many alerts to return. Values below 1 are raised to 1 and values above 200 are lowered to 200. Example 100 |
Response
The alerts.
| Field | Type | Description |
|---|---|---|
| alerts | array of Alert | The monitor's alerts, newest occurredAt first. [] when the monitor has raised none. |
| Status | Code | When |
|---|---|---|
| 401 | — | No valid X-API-Key header (or dashboard session token). Body: the Error object, detail a sentence. |
| 402 | — | The account has no active subscription and no active free trial. |
| 404 | — | No monitor with this id on your account: {"detail": "Monitor not found."}. |
curl "https://api.offendersearch.app/v1/monitors/mon_b8f40d7afb9dc0d8/alerts?limit=100" \
-H "X-API-Key: $OFFENDERSEARCH_KEY"{
"alerts": [
{ "id": "hit_7fa176c8889c7569", "eventType": "new", "matchLabel": "dob_match",
"record": { "name": "JORDAN RIVERA", "jurisdiction": "TX", "locality": "Houston",
"matchLabel": "dob_match", "matchConfidence": 1.0,
"personRef": "prs_3c9e1f0a7b2d4e6f8a1b", "recordId": "rec_ab12cd34ef56gh78ij90" },
"firstSeenAt": "2026-09-06T12:00:41+00:00",
"occurredAt": "2026-09-06T12:00:41+00:00",
"notifiedAt": "2026-09-06T12:01:03+00:00" }
]
}This history is not a consumer report and may not be used for any FCRA-covered decision.