# Searching by date of birth

> Add a dob and every record returns a labelled matchState: dob_match, year_match, age_match or no_dob_age_year — so you set your own confidence threshold.

- **HTML:** https://offendersearch.app/docs/date-of-birth
- **Base URL:** https://api.offendersearch.app
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **All documentation as markdown:** https://offendersearch.app/docs.md

## Searching by date of birth

A date of birth is the strongest identity verifier. Add `dob` (`YYYY-MM-DD`) to your `query` and every returned record carries a `matchState` telling you exactly how it matched. A record with no date of birth published is never silently dropped: if there is nothing to confirm the date but the name matched, you still get the record, labelled as unverified. Only a true conflict is excluded.

Jurisdictions publish identity at different resolutions — a full calendar date, a birth year, an age, or none of the three — and `matchState` names which one verified this record. That lets you set your own threshold for auto-accept versus review, rather than inherit one.

### matchState — how each record matched

| matchState | Meaning |
| --- | --- |
| `dob_match` | The record has a full date of birth on file and it equals the DOB you queried — the strongest confirmation. |
| `year_match` | The record has NO full DOB (a year-only source, e.g. Massachusetts), but its birth year equals your DOB’s year. |
| `age_match` | No DOB or birth year is published, but the record’s age matches the age implied by your DOB (±1 year for birthday drift). |
| `no_dob_age_year` | The record has no DOB, year, or age to verify against — yet it is still returned because the name matched. Check matchBasis for name_match or alias_match. This is the “no DOB on file, but the name matches” case. |
| `dob_mismatch` | The record HAD a DOB, year, or age and it did NOT match your query, so it is filtered OUT of the results. You will not normally see this state — it is documented so you know a true conflict is excluded, never silently shown. |
| `null` | You did not send a dob or an age, so there was nothing to verify the record against and this field carries no information. It is null, not a string — do not treat it as a failed verification. |

`matchState` is `null` when you did not supply a `dob` or `age`. A record whose date, year or age actively conflicts with your query is filtered out of `records[]`.

### dobVerification — the same signal, backward-compatible

`dobVerification` carries the raw token for integrations written before `matchState` existed. New code should read `matchState`.

| dobVerification | Meaning |
| --- | --- |
| `dob_match` | The record’s full date of birth equals the DOB you supplied — the strongest identity confirmation. |
| `year_match` | The record is year-only (dobPrecision: year) and its year equals your DOB’s year. |
| `age_match` | No full DOB was available, but the published age matched yours within ±1 year (birthday drift). |
| `no_dob_age_year` | The record had no DOB, age, or year to check against — kept and flagged (unverified: true). |
| `dob_mismatch` | The record had a DOB/age that did NOT match; such records are filtered out of records[], so you normally never see this. |

## dob, birthYear and dobPrecision

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 publishes | dob | birthYear | dobPrecision | Matches your dob query as |
| --- | --- | --- | --- | --- |
| A full calendar date | `"1961-09-25"` | `1961` | `"exact"` | `dob_match` |
| A birth year only | `null` | `1961` | `"year"` | `year_match` — any date you query inside that year |
| An age only | `null` | `null` | `"unknown"` | `age_match` — a date consistent with the published age |
| Neither date, year nor age | `null` | `null` | `"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, so you can hand it straight to a date parser. **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.

**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. `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`.

```json
{
  "query": {
    "firstName": "John",
    "lastName": "Doe",
    "dob": "1980-04-12",
    "ageTolerance": 2,
    "onAgeMismatch": "flag"
  },
  "match": "balanced"
}
```

## matchBasis — why each record is in the results

| matchBasis value | Meaning |
| --- | --- |
| `lastName:exact / firstName:exact` | The field equals the name you sent. |
| `lastName:prefix / firstName:prefix` | The field starts with the name you sent — a partial-name hit. See Partial name search. |
| `firstName:nickname` | Matched through a nickname equivalence (bob → Robert). |
| `lastName:fuzzy / firstName:fuzzy` | Matched through a spelling variant or typo. |
| `firstName:absent` | The record publishes no first name, so your first name could not be disproved — kept and flagged rather than dropped. |
| `alias:exact / alias:prefix` | An alias matched, not the registered name. Read matchedName to see which alias. |
| `name_match` | The record matched on its primary name — the name you searched. |
| `alias_match` | The record matched on one of its aliases rather than its primary name. |
| `unverified_no_dob_or_age` | The 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).

```json
{
  "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"
}
```

---

## Related

- Previous: [Matching, confidence & partial names](https://offendersearch.app/docs/matching.md)
- Next: [Result completeness & per-source status](https://offendersearch.app/docs/result-completeness.md)
- Index: [Offendersearch API documentation](https://offendersearch.app/docs.md)
