# Cached vs. live verification

> The stored copy answers in under a second. A live re-check asks the source now, costs more, and tells you exactly which sources answered.

- **HTML:** https://offendersearch.app/docs/guides/criminal/cached-vs-live
- **Base URL (live):** https://api.offendersearch.app — live keys (`os_live_…`)
- **Base URL (sandbox):** https://sandbox.offendersearch.app — test keys (`os_test_…`), never billed
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **Docs index for agents:** https://offendersearch.app/llms.txt

## Side by side

|  | Cached search | Live re-check |
| --- | --- | --- |
| Request | `POST /v1/criminal/search` with `query` | Add `live: { "jurisdictions": ["TX-DOC"] }` or `live: { "scope": "matched" }` |
| Reads | Every stored record that corroborates the surname — or refuses with `422 query_too_broad` | The named sources, at the source, now; up to two run inside the request, more answer `202` and are polled |
| Completeness | `status: "complete"`; `sourceStatus: []` | `sourceStatus[]` per live source: `code`, `ok`, `incomplete`, `incompleteReason`, `records`, `lastCheckedAt`, `live`; envelope `status: "partial"` if one fell short; `warnings[0]` begins `INCOMPLETE SEARCH:` |
| `incompleteReason` values | — | `source_down`, `timeout`, `truncated_over_cap`, `not_searched`, `unsupported_site` today; `captcha_unsolved`, `rate_limited`, `proxy_required`, `paid_gateway`, `login_required` reserved |
| Billing | One `criminal_call` | Plus one `criminal_live_source` per completed source |
| Use when | Screening at volume; a first answer | A contested or high-stakes decision; a source the catalog marks live-only; a point-in-time answer for the file |

Which sources can be re-checked live is in `GET /v1/criminal/jurisdictions?live=true` and the [coverage](/docs/criminal/coverage) page. A sweep-only source answers `not_searched` immediately rather than timing out. When a live source could not run but its stored records are in scope, the row is answered from file: `ok: true`, `live: false`, `answeredFrom: "on_file"`, and `liveOutcome` (an `incompleteReason` token, usually `not_searched`) says why the live check did not run; it is not billed and `warnings[]` gains a `LIVE CHECK NOT AVAILABLE:` sentence.

## Related

- [Async & long-running](https://offendersearch.app/docs/criminal/async)
- [Completeness & source status](https://offendersearch.app/docs/criminal/result-completeness)
