# 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 - one query reaches date, year and age evidence.

- **HTML:** https://offendersearch.app/docs/criminal/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
- **Criminal reference as markdown:** https://offendersearch.app/docs/criminal.md

## One query reaches every kind of birth evidence

Jurisdictions do not all publish a date of birth: some publish only a birth year, many jail and inmate records publish only an **age**, a few publish neither. **You do not have to compensate for that.** A `dob` you send is matched against a full date, else a year, else an age — so one query reaches all of them. Widening happens when we match; it never happens in what we store or send.

## matchState — how each record matched

| `matchState` | The record holds | Meaning | `unverified` |
| --- | --- | --- | --- |
| `dob_match` | a full date | The record's full date of birth equals yours. Strongest confirmation. | `false` |
| `year_match` | a year (and maybe a month) | The birth years agree (months too, if both publish one). Never a full-date confirmation. | `false` |
| `age_match` | only an age | The age is consistent with the date you sent (within ±1 year). A plausibility check, not a confirmation. | `false` |
| `no_dob_age_year` | nothing comparable | Nothing to check against — returned because the **name** matched. | **`true`** |
| `dob_mismatch` | conflicting evidence | A date, year or age that **conflicted** with your query. **Dropped — you never see this in `records[]`.** | — |

`matchState` is `""` when you queried no `dob`/`age`/`birthYear`. Every record also carries `unverified`, a coarse boolean twin: `true` iff `matchState == "no_dob_age_year"`.

## What you can send

| Field | Type | Notes |
| --- | --- | --- |
| `dob` | string `YYYY-MM-DD` | A full date. Matched against a full date, else a year, else an age. |
| `birthYear` | integer | A year on its own. |
| `birthMonth` | integer `1–12` | Refines a year match when both sides publish a month. Ignored unless a year is in play. |
| `age` | integer | Checked against age-only records, ±1-year tolerance. |

## dobPrecision — what kind of birth evidence a record carries

Every record reports the precision of its own date of birth. `dob.date` is a full `YYYY-MM-DD` date or it is `null` — **never a fabricated day**. A source that publishes a `1/1` sentinel collapses to `year` (or `age`, or `none`); the January-1st is never emitted as a real birthday, so you can hand `dob.date` to a date parser without a length check.

| `dobPrecision` | `dob.date` | `dob.birthYear` | `dob.age` |
| --- | --- | --- | --- |
| `full` | `"1989-04-23"` | `1989` | usually set |
| `month_year` | `null` | `1989` | maybe |
| `year` | `null` | `1989` | maybe |
| `age` | `null` | `null` | the published age |
| `none` | `null` | `null` | `null` |

## Records we could not verify are KEPT and flagged, not dropped

A DOB-filtered response is a **mixture** — `dob_match`, `year_match`, `age_match` and `no_dob_age_year` records side by side. Only a genuine **conflict** (`dob_mismatch`) is excluded. If you present the result as "confirmed matches", the unverified records make that claim false.

```js
const verified   = res.records.filter(r => !r.unverified);
const candidates = res.records.filter(r =>  r.unverified);
```

---

## Related

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