Offendersearch
API Reference · v1.0.0

Searching by date of birth

Labelled match strength on every record, and how dob, birthYear and dobPrecision fit together.

Base URL https://api.offendersearch.appThis page as Markdown/docs/date-of-birth.md

What comes back on the record: dob, birthYear, age

Jurisdictions differ in how much of a birth date they publish, so three fields carry the answer and which of them is populated is itself information. Read dobPrecision to know which case you are in.

What the jurisdiction publishesdobbirthYeardobPrecisionMatches your dob query as
A full calendar date"1961-09-25"1961"exact"dob_match
A birth year onlynull1961"year"year_match — any date you query inside that year
An age onlynullnull"unknown"age_match — a date consistent with the published age
Neither date, year nor agenullnull"unknown"no_dob_age_year — kept on the name, unverified: true
dob is a full YYYY-MM-DD date or null — never a bare year, never a partial date, and never a day and month chosen to fill the field. You can hand it straight to a date parser without a shape check. Where a jurisdiction publishes only the year, that year is in birthYear as an integer, and the record still matches a full-date query. Read birthYear for any year logic — it is populated both from a published year and from the year of a published date, so your code never has to branch on which kind of record it is looking at. It is never inferred from an age: an age is not a date, and this field is served as fact rather than as an estimate.

Age tolerance

Where a jurisdiction publishes an age and no date, a name + dob search compares your date against that published age, and ageTolerance (0–10, default 1) sets how much slack that comparison allows — a risk decision that belongs to you. onAgeMismatch decides what happens to a record that matches on name but whose published age contradicts your date: "drop" omits it, "flag" returns it labelled matchState: "age_mismatch" and always unverified, so you can judge it yourself.

A high-recall identity check
{
  "query": {
    "firstName": "John",
    "lastName": "Doe",
    "dob": "1980-04-12",
    "ageTolerance": 2,
    "onAgeMismatch": "flag"
  },
  "match": "balanced"
}

matchBasis — why each record is in the results

Alongside matchState, every record carries a matchBasis array explaining why it is in the result set. When there is no date of birth to verify, this is how you tell a name hit apart from a verified one:

matchBasis valueMeaning
lastName:exact / firstName:exactThe field equals the name you sent.
lastName:prefix / firstName:prefixThe field starts with the name you sent — a partial-name hit. See Partial name search.
firstName:nicknameMatched through a nickname equivalence (bob → Robert).
lastName:fuzzy / firstName:fuzzyMatched through a spelling variant or typo.
firstName:absentThe record publishes no first name, so your first name could not be disproved — kept and flagged rather than dropped.
alias:exact / alias:prefixAn alias matched, not the registered name. Read matchedName to see which alias.
name_matchThe record matched on its primary name — the name you searched.
alias_matchThe record matched on one of its aliases rather than its primary name.
unverified_no_dob_or_ageThe record was kept without DOB/age verification because there was nothing on file to check against — paired with matchState = no_dob_age_year.

matchBasis also carries lastName, firstName, and dob tokens indicating which identity fields the record itself provides. So a name hit with no date of birth reads as matchState: "no_dob_age_year" with matchBasis: ["...", "name_match"] (or alias_match when the match was on an alias).

A date-of-birth search never silently drops a name hit. If a record has no date, year, or age to confirm, you still get it with matchState: "no_dob_age_year" and a name_match/alias_match basis. Only a genuine conflict (dob_mismatch) is excluded from the results.
No date of birth published, but the name matches
{
  "matchState": "no_dob_age_year",
  "matchBasis": ["lastName", "firstName", "unverified_no_dob_or_age", "name_match"],
  "unverified": true,
  "name": { "first": "John", "last": "Doe", "full": "John Doe" },
  "dob": null,
  "dobPrecision": "unknown"
}

Jurisdiction is a filter too. Name the jurisdiction(s) you want with jurisdictions (e.g. ["MA", "NY"]), or set query.state with locationScoped: true to run only the jurisdictions covering that state. Omit jurisdictions to search the full dataset.