Sex Offender Search API · v1.0.0

Understanding search results

Read the envelope before the records. The order matters.

Read in this order

  1. `status`. complete: every source in scope finished. partial: at least one did not; records[] is a lower bound. (pending/running appear only while polling an async job; error means the job failed and nothing was billed for it.)
  2. `counts`. records matched in total, recordsReturned on this page, sourcesQueried, sourcesComplete, sourcesIncomplete, sourcesSkippedByScope, and clearedSuppressed when clearances applied.
  3. `sourceStatus[]`. One row per source: source (jurisdiction code), status (ok, error, restricted, no_coverage on a cached row; complete or partial on a live re-check row), matched, fromCache, note, incomplete, incompleteReason (deadline, truncated, excluded, not_searched, unavailable, error) and cappedOmitted. status: "ok" says the registry answered, not that it finished — read incomplete.
  4. `records[]`. Best first. Each is a candidate with the match explained.
  5. `warnings[]`, `capped`. Plain sentences for anything that shortened the answer; capped: true with cappedReason: "responseLimit" when the 4,000-record cap applied. Both empty on a normal search.

How a record matched

FieldValuesUse it to
matchConfidence0–1, null when the search named nobody (radius, free text)Rank and threshold. A prefix match is capped below an exact one.
matchBasis[]e.g. lastName:exact, firstName:nickname, alias:prefix; dob appears as a bare token when the record carries one (how it agreed is matchState)Explain the match to a reviewer. Prefer matchDetail.strategies for a per-field answer.
matchStatedob_match, year_match, age_match, no_dob_age_year, age_mismatch, dob_mismatchTier the review queue by how the birth date agreed. Only present when you sent dob or age.
matchedName{ value, type: "legal" | "alias" }Show which name matched.
dobPrecisionexact, year, year_month, unknownKnow how much birth date the source published; never compare a year record as a full date.
unverifiedbooleanThe record could not be checked against the identifiers you sent (no published DOB or age).

matchDetail.strategies carries one key per name field you sent (lastName, firstName) with how it matched (exact, nickname, initial, prefix, fuzzy, middle, absent); the birth date is not a strategy — its agreement is matchState (also echoed as matchDetail.verification). Gate an automatic decision on strategies and matchState, not on matchConfidence alone.

When records[] is non-empty and counts.sourcesIncomplete > 0, treat the result as both: the candidates are real and must be reviewed, and the answer is a lower bound, so carry the incomplete sources with the outcome (or re-run with live on those registries) rather than reporting clear or dropping the candidates.

What a record carries

name (first, middle, last, suffix, full), aliases[], nicknames[], dob, birthYear, age, physical descriptors, addresses[], registrationState, addressStates[], offenses[] (crime, statute, convictionDate, offenseDate, registrationDate, …), flags (absconder, predator), housingStatus, images[], and sources[] with jurisdiction, registryName, recordUrl and lastCheckedAt. stateData is present on every record (exclude: ["stateData"] drops it for a lighter payload). Every field: the Record object.

The decision each answer supports

AnswerMeansDoes not mean
complete, records: []No registrant matched in any source searched.That the person is not registered anywhere; coverage is what the catalog says it is.
partial, records: []No match in the sources that finished.A clear result. Re-check the incomplete sources.
Records with dob_matchA registrant with this name whose published birth date equals the one you sent.Confirmed identity. Names and birth dates repeat.
Records with year_match / age_match / no_dob_age_yearName agreed; birth date partly or not at all.A match to act on without review.

Product overview