Evidence and supporting documents
The registry's own website, printed to one PDF per registry behind a cover page with a hash. Asynchronous, polled, and downloadable for 30 days.
When to use this
A verification report says what the platform found. Evidence shows what the registry itself displayed at that moment: every result page and each matching registrant's detail page, printed as shown, behind a cover page carrying the capture time and a SHA-256 of the document. Compliance teams ask for it when a decision may be questioned later. You will build the flow: send live.evidence: "pdf" with the registries to print, poll the job, read evidence[], download each PDF and store it with its hash.
Before you start
- A test key. On the sandbox the documents are fixed
SAMPLEPDFs, the first poll is alreadycomplete, andbilledisfalse. - The request is an ordinary
POST /v1/searchwith aliveblock that hasevidence: "pdf"and `jurisdictions` naming at most 20 registries.live.scopeis refused for evidence (422), andquery.lastNameis required. - Price: $0.25 per completed document, at most $5.00 per search, on top of the live search's own charge ($0.02 per completed source). An incomplete document bills nothing (pricing).
202, never a SearchResponse. The searchId begins evs_, the records and the documents arrive on GET /v1/searches/{searchId} (the pollUrl), and the download link in each evidence[] entry works for 30 days. Treat the 202 as a job handle and persist it.Step by step
- Submit. Search Exact Match with
dob1980-01-01and"live": {"jurisdictions": ["OH"], "evidence": "pdf"}. Store theevs_id from the202. - Poll.
GETthepollUrlevery 2–5 seconds. Whilepending/runningthe body has zeroed counts andevidence: []; when finished it is the liveSearchResponseplusevidence[],usage.liveEvidence,usage.liveEvidenceUsdandsourceSearchId. - Read `evidence[]`. One entry per registry:
completewithdownloadUrl,sha256,pagesand often an inlinepdfBase64; orincompletewith anincompleteReasonandbilled: false. - Download and file.
GET /v1/searches/{evs_id}/evidence/{CODE}.pdfreturns the PDF (application/pdf); verify the SHA-256 and store it with theevs_id and thesourceSearchId.
Steps 1–4 in code
# 1. submit → 202
curl -s https://sandbox.offendersearch.app/v1/search \
-H "X-API-Key: $OFFENDERSEARCH_KEY" -H "Content-Type: application/json" \
-d '{"query": {"firstName": "Exact", "lastName": "Match", "dob": "1980-01-01"},
"live": {"jurisdictions": ["OH"], "evidence": "pdf"}}'
# 2. poll the pollUrl from the 202
curl -s https://sandbox.offendersearch.app/v1/searches/evs_41dabad43b4cdfd43e663573 -H "X-API-Key: $OFFENDERSEARCH_KEY"
# 4. download one registry's document
curl -s -o evidence-OH.pdf https://sandbox.offendersearch.app/v1/searches/evs_41dabad43b4cdfd43e663573/evidence/OH.pdf \
-H "X-API-Key: $OFFENDERSEARCH_KEY"{
"searchId": "evs_41dabad43b4cdfd43e663573",
"status": "pending",
"mode": "async",
"registries": ["OH"],
"pollUrl": "/v1/searches/evs_41dabad43b4cdfd43e663573",
"sandbox": true
}{
"searchId": "evs_41dabad43b4cdfd43e663573",
"status": "running",
"registries": ["OH"],
"counts": { "records": 0, "sourcesQueried": 58, "sourcesIncomplete": 0 },
"records": [],
"sourceStatus": [],
"evidence": []
}{
"searchId": "evs_41dabad43b4cdfd43e663573",
"status": "complete",
"counts": { "records": 1, "recordsReturned": 1, "sourcesQueried": 58, "sourcesComplete": 58, "sourcesIncomplete": 0, "sourcesSkippedByScope": 0 },
"sourceStatus": [
{ "source": "OH", "status": "complete", "matched": 1, "fromCache": false, "incomplete": false, "incompleteReason": null }
],
"records": [ { "recordId": "rec_28db9639d712c4c61e8e", "personRef": "prs_28db9639d712c4c61e8e", "matchState": "dob_match", "matchConfidence": 0.9 } ],
"warnings": [],
"usage": { "liveChecks": 1, "liveChargeUsd": 0.02, "capped": false, "display": "1 live checks · $0.02",
"liveEvidence": 0, "liveEvidenceUsd": 0.0 },
"meterEvents": [],
"sourceSearchId": "srch_42006068f66b3f51abf41f49",
"evidence": [
{
"jurisdiction": "OH",
"status": "complete",
"kind": "text",
"pages": 2, "resultPages": 1, "detailPages": 1,
"capturedAt": "2026-10-01T12:00:00+00:00",
"sourceUrl": "https://offendersearch.app/docs/sandbox",
"pageUrls": [],
"sha256": "c48fa5f9921ccead4acfec7191378776adc5210c8f0544bd2eab6923a2e47e28",
"bytes": 2195,
"downloadUrl": "/v1/searches/evs_41dabad43b4cdfd43e663573/evidence/OH.pdf",
"billed": false,
"chargeUsd": 0.0,
"pdfBase64": "JVBERi0xLjMKJenr…",
"inline": true
}
],
"sandbox": true
}In production a completed document has billed: true, chargeUsd: 0.25, and usage.liveEvidence / usage.liveEvidenceUsd count it (min(n × 0.25, 5.00)). sourceSearchId is the live search on your account that produced records[] — that id, not the evs_ id, is what POST /v1/report and a clearance cite. pdfBase64 is present when the document is 4 MB or smaller (inline: true); above that, use downloadUrl.
{
"jurisdiction": "NV",
"status": "incomplete",
"incompleteReason": "source_unreachable",
"detail": "the registry website did not answer within the time allowed",
"billed": false
}HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="offendersearch-evidence-evs_41dabad43b4cdfd43e663573-OH.pdf"Reading the result
| Field | Values | What to do |
|---|---|---|
evidence[].status | complete, incomplete | Download on complete; read incompleteReason otherwise. |
evidence[].incompleteReason | renderer_unavailable, source_unreachable, timed_out | Transient — retry the evidence search for that registry. |
blocked, no_results_page, render_failed, query_unsupported, no_recipe | Not fixed by retrying: the site refused the visit, showed no results page for this query, could not be printed, cannot search on these fields, or cannot be printed yet. Record the reason. | |
evidence[].sha256 | hex | Verify the download; the same value is printed on the cover page. |
evidence[].kind | text, image, mixed | text is searchable; image is a full-page capture (some registries only work this way). |
evidence[].pages / resultPages / detailPages | integers | What the document holds, after the cover page. |
evidence[].downloadUrl | path | GET it with your key within 30 days; 404 afterwards, for another account, or for an incomplete document. |
usage.liveEvidence, usage.liveEvidenceUsd | integer, number | Billed documents and the charge, separate from liveChargeUsd. |
sourceSearchId | srch_… | The citable search behind the records. |
Edge cases and pitfalls
- `live.scope` is a `422` here:
live.scope is not supported for evidence; name the registries in live.jurisdictions. Run the Regular search first, readregistrationStatefrom the hits, then request evidence for those registries. - Capacity: the evidence service answers
429withRetry-After: 10when it is busy. Nothing ran; wait and resubmit. - Unavailable:
503with{"error": {"code": "unavailable", "message": "…"}}— not the usualdetailenvelope. The search was not run and nothing was billed; retry, or omitlive.evidence. - A job that does not finish within 15 minutes polls as
status: "error"witherror: "the job did not finish; nothing was billed for it". Resubmit. - Up to 20 registries per search. Split a longer list into several evidence searches; each has its own $5.00 ceiling.
- The main host's request validation is not applied to an evidence request — an unknown
jurisdictions[]code or amatchtypo in the same body is not refused by it. Validate the body as you would forPOST /v1/searchbefore sending. - Poll with an API key.
GET /v1/searches/{evs_id}on the main host does not accept a dashboard session. - 30 days is the document's life, longer than the 14-day search retention and the 7-day report window. Download and store what you need to keep.
Production checklist
evs_id persisted on the202; poller with a 2–5 s interval and a 15-minute cap.- Every
completedocument downloaded, hash-verified and stored withevs_id,sourceSearchId,capturedAtandsha256. - Every
incompletereason recorded; transient reasons retried once. usage.liveEvidenceUsdreconciled against Dashboard → Usage.
Related products
Product overview
- Sex offender search API
- Sex offender registry API
- Offender search API
- Background check API
- Bulk sex offender search
- Background check API pricing
- Background check API integration
- Integrations
- Free background check API
- Pay-as-you-go background check API
- Background check API in Python
- Background check API in Node.js
- NSOPW API