Monitoring API · v1.0.0

Quickstart

Your first monitor in three languages, and the alert it delivers when a record matches.

Livehttps://api.offendersearch.appSandboxhttps://sandbox.offendersearch.app

Authenticate

Every request carries your secret key in the X-API-Key header — the same key you already use for the Sex Offender API and the Criminal Search API. Monitoring is a product on your existing account, not a separate credential. Create a key in your dashboard and export it.

export OFFENDERSEARCH_BASE=https://api.offendersearch.app
export OFFENDERSEARCH_KEY="os_live_…"

Create your first monitor

A monitor is a standing watch. This one watches the sex-offender dataset for one person by name and date of birth, and delivers an alert whenever a matching record appears, changes, or comes off a registry. product, type, the predicate and at least one channel are required.

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" },
        "minConfidence": "dob_match",
        "label": "Jordan Rivera — SO watch",
        "channels": { "email": "alerts@example.com" }
      }'

The response is the Monitor object with 201 Created. It is active immediately and evaluated once per day from then on.

201 Created
{
  "id": "mon_b8f40d7afb9dc0d8",
  "product": "sex-offender",
  "type": "person",
  "minConfidence": "dob_match",
  "label": "Jordan Rivera — SO watch",
  "status": "active",
  "channels": { "emails": ["alerts@example.com"] },
  "createdAt": "2026-09-05T14:02:11+00:00",
  "canceledAt": null,
  "person": { "firstName": "Jordan", "lastName": "Rivera", "dob": "1988-04-12" }
}

Receive an alert

When the daily evaluation finds a matching record, an alert is delivered to every channel on the monitor. This is the JSON body POSTed to a webhook — the monitor.alert payload. Its detail is the same record summary the alert-history endpoint returns as record.

Alert payload
{
  "type": "monitor.alert",
  "event": "new",
  "alertId": "hit_7fa176c8889c7569",
  "monitorId": "mon_b8f40d7afb9dc0d8",
  "monitorLabel": "Jordan Rivera — SO watch",
  "product": "sex-offender",
  "detail": {
    "name": "JORDAN RIVERA",
    "jurisdiction": "TX",
    "locality": "Houston",
    "matchLabel": "dob_match",
    "matchConfidence": 1.0,
    "personRef": "prs_3c9e1f0a7b2d4e6f8a1b",
    "recordId": "rec_ab12cd34ef56gh78ij90"
  },
  "occurredAt": "2026-09-06T12:00:41+00:00",
  "sentAt": "2026-09-06T12:01:03+00:00"
}

Read the alert, in this order, every time

  1. event — new (a matching record newly appeared), changed (a monitored record’s details changed), or removed (it no longer matches). It tells you what happened before you read the record.
  2. detail.matchLabel — how strongly identity matched: dob_match is the full date of birth, year_match the birth year only, age_match a published age, name_match the name alone. A monitor only alerts at or above its minConfidence floor. See Person monitoring.
  3. detail — the matched record, summarised: the name, a neutral jurisdiction code, the city, and the personRef to recognise the person by next time. On a removed event it carries only event and jurisdiction.
  4. monitorId — which monitor fired, so one webhook endpoint can serve many monitors.
  5. occurredAt — when this record first matched the monitor, in ISO-8601.
Monitoring alerts are not a consumer report and may not be used for any FCRA-covered decision — this matters most here, because a monitor runs unattended. Every alert email carries that notice in its footer. See Access, keys & data handling.

Where to go next

  • Person monitoring — name + DOB, and why a DOB matters.
  • Location monitoring — watch a radius around an address.
  • Alerts — the event types, the daily cadence and de-duplication.
  • Billing — the price matrix and the one-predicate-one-charge rule.

Test the monitoring API in the sandbox

Create person and location monitors on the sandbox with a test key (os_test_…). A sandbox monitor is checked once, at creation: each match is filed as a new alert and sent to your webhook, and a sandbox-only test event sends another.

Base URL
https://sandbox.offendersearch.app Not https://api.offendersearch.app, which takes live keys only.
Test key
In the dashboard, Developers → API keys → Create test key. Test keys begin os_test_; send yours in the X-API-Key header.
POST /v1/monitors
curl -X POST "https://sandbox.offendersearch.app/v1/monitors" \
  -H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "product": "sex-offender",
      "type": "person",
      "person": {
        "firstName": "Exact",
        "lastName": "Match",
        "dob": "1980-01-01"
      },
      "channels": {
        "webhookUrl": "https://your-app.example.com/hooks/offendersearch"
      }
    }'

Try it here

Pick a scenario, edit the request, and run it against the sandbox from this page. The explorer accepts os_test_ keys only and never reaches the live host, so nothing here is billed; the “production” code it copies is for your own backend with a live key.

Create a test key under Dashboard → API keys. Live keys are refused here.
Copy this request as code

Sandbox code uses your test key. Production code calls the live host and is billed per call; run it from your backend with an os_live_… key.

curl -X POST https://sandbox.offendersearch.app/v1/monitors \
  -H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "product": "sex-offender", "type": "person", "person": { "firstName": "Exact", "lastName": "Match", "dob": "1980-01-01" }, "channels": { "webhookUrl": "https://your-app.example.com/hooks/offendersearch" } }'

Product overview