# Criminal Search API reference

> Every Criminal Search API endpoint and object in one index: what each request sends, what each response returns, and a link to every field definition.

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

## How the criminal records API reference is organised

Every endpoint documents what it is sent and what it returns in two tables, next to the guide that explains it. Shared objects — the CriminalRecord that search, batch and the record lookup return, its cases and charges, the live `SourceStatus`, the `Error` body — are defined once and linked from every table that carries them.

## Criminal search API endpoints — request and response fields

Each endpoint links to its reference block: a Request table (path, query and body fields, with type, required and default) and a Response table (every field, with type and when it is null). Every endpoint takes the `X-API-Key` header except `GET /v1/criminal/sources`.

| Endpoint | What it does |
| --- | --- |
| [`POST /v1/criminal/search`](https://offendersearch.app/docs/criminal/search#reference-post-v1-criminal-search) | **Search.** Search criminal records for one person. Without a `live` block it returns the cached answer; with one it re-verifies the named jurisdictions at the source during the request. Bills one `criminal_call`, plus $0.02 per completed live source up to $2.00. |
| [`GET /v1/criminal/searches/{searchId}`](https://offendersearch.app/docs/criminal/async#reference-get-v1-criminal-searches-searchid) | **Get an async search.** Read an async live job. Returns `202` while it runs and `200` with the full envelope in `result` once every source has an outcome. Polling is free. |
| [`POST /v1/criminal/batch`](https://offendersearch.app/docs/criminal/batch#reference-post-v1-criminal-batch) | **Batch.** Run up to 1,000 cached searches in one request, one result per row in input order. Each row that runs bills one `criminal_call`. Live verification is not available in a batch. |
| [`GET /v1/criminal/records/{recordId}`](https://offendersearch.app/docs/criminal/record-object#reference-get-v1-criminal-records-recordid) | **Get a record.** Fetch one current record by its `externalId`, sending its `sources[].code` as `source` so the lookup is a direct key read. The record comes back unscored: `matchConfidence` is `0.0` and the match fields are empty, because there is no query to score against. Not billed. |
| [`GET /v1/criminal/sources`](https://offendersearch.app/docs/criminal/coverage#reference-get-v1-criminal-sources) | **List sources.** The coverage catalog: every source by public code, whether it is available, and when its records were last updated. No API key needed, so coverage can be checked before you sign up. Not billed. |
| [`GET /v1/criminal/jurisdictions`](https://offendersearch.app/docs/criminal/jurisdictions#reference-get-v1-criminal-jurisdictions) | **List jurisdictions.** Every covered jurisdiction by public code, state, county and record kind, filtered by the query parameters. Not billed. |
| [`POST /v1/criminal/resolve`](https://offendersearch.app/docs/criminal/resolve#reference-post-v1-criminal-resolve) | **Resolve a website.** Map a roster or records website you already use to the public jurisdiction code that covers it, or say it is not covered. Not billed. |
| [`GET /v1/criminal/history`](https://offendersearch.app/docs/criminal/verification-reports#reference-get-v1-criminal-history) | **Search history.** Your account's 50 most recent criminal searches, newest first, with the `searchId` a report needs. Not billed. |
| [`POST /v1/criminal/report`](https://offendersearch.app/docs/criminal/verification-reports#reference-post-v1-criminal-report) | **Verification report.** Render a PDF that records a search was run: the criteria, the sources searched and the records found (for a stored `searchId`, the page that search returned), with the not-a-consumer-report notice. A report on a stored `searchId` bills only the report; an inline `query` bills the search too. |

## Criminal search API objects — CriminalRecord, Case, SourceStatus and more

Each object is defined once, on the page linked here. Wherever an endpoint or another object carries it, the type links back to that one definition.

| Object | What it is |
| --- | --- |
| [`Error`](https://offendersearch.app/docs/criminal/errors#object-error) | The body of every error the criminal service returns: one nested `error` object with a stable `code` to branch on and a `message` to log or show. A `401` or `402` comes from the gateway in the [GatewayError](https://offendersearch.app/docs/criminal/errors#object-gatewayerror) shape instead. |
| [`GatewayError`](https://offendersearch.app/docs/criminal/errors#object-gatewayerror) | The body of a `401` (missing or invalid `X-API-Key`) or a `402` (free trial used up, or no active subscription). The gateway answers these before the criminal service runs, so the shape is the Sex Offender API's flat `detail` string. |
| [`Query`](https://offendersearch.app/docs/criminal/search#object-query) | The person you are looking for. `lastName` is the only required field; every other field narrows within that surname. Send it as `query` on [POST /v1/criminal/search](https://offendersearch.app/docs/criminal/search#reference-post-v1-criminal-search) and [POST /v1/criminal/report](https://offendersearch.app/docs/criminal/verification-reports#reference-post-v1-criminal-report), or as one row of `queries[]` on [POST /v1/criminal/batch](https://offendersearch.app/docs/criminal/batch#reference-post-v1-criminal-batch). The fields can also be sent flat at the top level of the body. |
| [`LiveRequest`](https://offendersearch.app/docs/criminal/async#object-liverequest) | The `live` block. Its presence turns on live verification: the named jurisdictions are re-checked at the source during the request and the fresh results merge with the cached answer through the same matcher. Up to 2 sources that can answer quickly run synchronously (`200`); more, or any source that cannot, run as an async job (`202`). |
| [`Counts`](https://offendersearch.app/docs/criminal/result-completeness#object-counts) | Totals on every criminal search. The three live counts are `0` on a cached search; `sourcesOnFile` and `sourcesPending` describe the sources behind the answer on every search. |
| [`SearchCoverage`](https://offendersearch.app/docs/criminal/result-completeness#object-searchcoverage) | Which sources stand behind a search for the state or county searched, and which sources for that scope are not available yet. Codes are the public codes [GET /v1/criminal/sources](https://offendersearch.app/docs/criminal/coverage#reference-get-v1-criminal-sources) lists. It does not change `status`. |
| [`SearchCoverageSource`](https://offendersearch.app/docs/criminal/result-completeness#object-searchcoveragesource) | One source in a search's coverage block. |
| [`SourceStatus`](https://offendersearch.app/docs/criminal/result-completeness#object-sourcestatus) | One live source's outcome within a search. Present only on a live search; a cached search returns `sourceStatus: []`. |
| [`ResolutionEntry`](https://offendersearch.app/docs/criminal/resolve#object-resolutionentry) | What one website resolved to, as reported in a search's `resolution[]`. The same fields as a [ResolveResult](https://offendersearch.app/docs/criminal/resolve#object-resolveresult) without `state` and `county`. |
| [`Usage`](https://offendersearch.app/docs/criminal/async#object-usage) | The live-check count and charge, present only on a live search. The count is the true number of completed checks even when the charge is capped. |
| [`MeterEvent`](https://offendersearch.app/docs/criminal/async#object-meterevent) | One billable unit this request emitted. |
| [`Legal`](https://offendersearch.app/docs/criminal/api-reference#object-legal) | The notice carried on every criminal search response and every batch row. |
| [`CriminalRecord`](https://offendersearch.app/docs/criminal/record-object#object-criminalrecord) | One record from one jurisdiction, as search, batch and the record lookup return it. A person found in several jurisdictions (booked in one county, a court case in another, an inmate record statewide) comes back as one record per jurisdiction; relate them by name, `dob` and `state`. Every key is present on every record. Empties mean different things: `""` is a text field the source does not publish, `null` is a date, number, object or demographic that is not known, and `[]` is a list with nothing on file. |
| [`Name`](https://offendersearch.app/docs/criminal/record-object#object-name) | A name in four parts, each `""` when not published. There is no `full` key; join the parts for display. Casing is as published; matching ignores case. |
| [`Dob`](https://offendersearch.app/docs/criminal/record-object#object-dob) | All birth evidence on a record. `dobPrecision` says which parts are real; `date` is a full date or `null`, never a made-up day. A source's placeholder date (`1/1` of a year with nothing else to support it, and the like) never becomes a full `date`; a sentinel (`1900-01-01`, `0001-01-01`, any `9999` date, a year before 1900 or after this year) is no birth evidence, so `birthYear` is `null` too. |
| [`Address`](https://offendersearch.app/docs/criminal/record-object#object-address) | A residence, in the same slots as the Sex Offender API's address. Text fields are `""` when not published. |
| [`Case`](https://offendersearch.app/docs/criminal/record-object#object-case) | A court case and its charges. `filedDate` is ISO or `null`; text fields are `""` when not published. |
| [`Sentence`](https://offendersearch.app/docs/criminal/record-object#object-sentence) | A sentence. Text fields are `""` when not published; dates are ISO or `null`. |
| [`Parole`](https://offendersearch.app/docs/criminal/record-object#object-parole) | Parole posture as published. Dates are ISO or `null`; text fields `""` when not published. |
| [`Custody`](https://offendersearch.app/docs/criminal/record-object#object-custody) | Custody classification, alongside `currentStatus` and `custodyFacility`. Text fields `""` when not published. |
| [`Charge`](https://offendersearch.app/docs/criminal/record-object#object-charge) | One charge on a case. `severity: null` means the source did not classify it, not that it is minor. |
| [`SourceRef`](https://offendersearch.app/docs/criminal/record-object#object-sourceref) | The jurisdiction a record comes from. `code` names a state and a place, nothing else. |
| [`Lifecycle`](https://offendersearch.app/docs/criminal/record-object#object-lifecycle) | Records are never deleted when a person leaves a source; the departure is reported here and the record is still returned. |
| [`Coverage`](https://offendersearch.app/docs/criminal/coverage#object-coverage) | Coverage totals for the whole product, by jurisdiction. |
| [`SourceInfo`](https://offendersearch.app/docs/criminal/coverage#object-sourceinfo) | One source in the coverage catalog. |
| [`JurisdictionInfo`](https://offendersearch.app/docs/criminal/jurisdictions#object-jurisdictioninfo) | One covered jurisdiction: its public code and its place, nothing else. |
| [`ResolveResult`](https://offendersearch.app/docs/criminal/resolve#object-resolveresult) | What one website resolved to. The response names the state, the county and the public code, never the website's host. |
| [`ResolveListResponse`](https://offendersearch.app/docs/criminal/resolve#object-resolvelistresponse) | The answer when `websites` (a list) is sent. |
| [`JobRecord`](https://offendersearch.app/docs/criminal/async#object-jobrecord) | An async live job as [GET /v1/criminal/searches/{searchId}](https://offendersearch.app/docs/criminal/async#reference-get-v1-criminal-searches-searchid) returns it: `pending` with `result: null` until every source has an outcome, then `complete` with the full search envelope in `result`. |
| [`HistoryEntry`](https://offendersearch.app/docs/criminal/verification-reports#object-historyentry) | One prior criminal search. Pass `searchId` to [POST /v1/criminal/report](https://offendersearch.app/docs/criminal/verification-reports#reference-post-v1-criminal-report) to render it. |
| [`BatchRow`](https://offendersearch.app/docs/criminal/batch#object-batchrow) | One row's result. A row that ran is the search envelope without `searchId`, `meterEvents`, `usage` and `resolution`, plus `index`. A row that failed validation carries only `index`, `status: "error"`, `error`, zeroed `counts` and `records: []`. |
| [`ClearedEntry`](https://offendersearch.app/docs/criminal/clearances#object-clearedentry) | One record a `not_this_person` clearance removed from `records[]` for the `subjectId` sent. `cleared[]` carries one of these per suppressed record, so an interface can say how many previously cleared people are hidden and link each to its clearance. |
| [`RecordClearance`](https://offendersearch.app/docs/criminal/clearances#object-recordclearance) | The clearance that names a record's person, attached as `clearance` when the request carried `subjectId` and the record was kept: in `clearanceMode: "annotate"`, on a `this_person` verdict, or because a cleared person has re-surfaced (`staleReason` set). A record no clearance names carries no `clearance` key. |

## The Legal object — the FCRA notice

The notice carried on every criminal search response and every batch row.

Returned or accepted by [`POST /v1/criminal/search`](https://offendersearch.app/docs/criminal/search#reference-post-v1-criminal-search), [`GET /v1/criminal/searches/{searchId}`](https://offendersearch.app/docs/criminal/async#reference-get-v1-criminal-searches-searchid), [`POST /v1/criminal/batch`](https://offendersearch.app/docs/criminal/batch#reference-post-v1-criminal-batch).

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `notice` | `string` |  | The not-a-consumer-report notice, verbatim. This data may not be used for any FCRA purpose: employment, tenant screening, credit, insurance or any other FCRA-covered decision. Example `"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.)."`. |

---

## Related

- Previous: [Batch & CSV search](https://offendersearch.app/docs/criminal/batch.md)
- Next: [The Criminal Record object](https://offendersearch.app/docs/criminal/record-object.md)
- Index: [Criminal Search API reference](https://offendersearch.app/docs/criminal.md)
