# Quickstart

> Make your first criminal-records search in cURL, and learn the five checks to run on every response: status, sourcesIncomplete, warnings, counts, matchState.

- **HTML:** https://offendersearch.app/docs/criminal/quickstart
- **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

## Authenticate

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

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

## Your first search

`query.lastName` is required. A nameless query is declined with `422 guard_unbounded_query` rather than answered with an arbitrary slice. `page` and `perPage` are top-level request fields, not inside `query`.

```bash
curl -X POST "$OFFENDERSEARCH_BASE/v1/criminal/search" \
  -H "X-API-Key: $OFFENDERSEARCH_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "query": { "lastName": "Hamilton", "firstName": "Alex", "state": "TX" },
        "page": 1, "perPage": 50
      }'
```

The default is the **cached** answer: it consults no live source, so `status` is `complete` and `sourceStatus` is `[]`.

```json
{
  "status": "complete",
  "counts": { "records": 12, "recordsReturned": 12,
              "sourcesQueried": 0, "sourcesComplete": 0, "sourcesIncomplete": 0 },
  "warnings": [],
  "page": 1, "perPage": 50, "totalPages": 1,
  "sourceStatus": [],
  "records": [ "… up to perPage normalized records, each with a matchState …" ],
  "searchId": "crs_7f2a1c9e0b4d6a8f1e23",
  "legal": { "notice": "Not a consumer report. This information may not be used for any purpose under the Fair Credit Reporting Act (15 U.S.C. § 1681 et seq.)." }
}
```

## Read the response, in this order, every time

1. **`status`** — `"complete"` means the search finished. `"partial"` means at least one **live** source could not be checked to the end. A cached search is always `"complete"`.
2. **`counts.sourcesIncomplete`** — `> 0` means one or more live sources fell short, so an empty result is a **lower bound**, not a confirmed absence. Always `0` on a cached search.
3. **`warnings`** — `[]` means nothing shortened this answer, so `warnings == []` is a valid completeness assertion. Any entry begins `INCOMPLETE SEARCH:` and names the sources.
4. **`counts.records`** — the total matched, before your page slice. `records.length` (and `counts.recordsReturned`) is only the current page.
5. **Per record: `matchState`, `matchConfidence`, `matchBasis`** — did the date of birth verify, and how did the name match?

## Get the per-source annex

The light response omits the per-source annex and names it in `omittedFields` (`["sourceData"]` by default). Send `include: ["sourceData"]` to un-omit it; nothing else is ever held back.

## Where to go next

- [Search](https://offendersearch.app/docs/criminal/search.md) — every parameter, both modes, and worked examples.
- [Matching & confidence](https://offendersearch.app/docs/criminal/matching.md) — the required surname anchor and the confidence arithmetic.
- [Date of birth](https://offendersearch.app/docs/criminal/date-of-birth.md) — how one `dob` query reaches date, year and age evidence.
- [Completeness & source status](https://offendersearch.app/docs/criminal/result-completeness.md) — what an empty live result does not mean.
- [Coverage today](https://offendersearch.app/docs/criminal/coverage.md) — the public source of truth for what is covered right now.

---

## Related

- Next: [Access & keys](https://offendersearch.app/docs/criminal/authentication.md)
- Index: [Criminal Search API reference](https://offendersearch.app/docs/criminal.md)
