# Verification reports

> Generate a branded, timestamped PDF of a search you already ran, with a source citation on every record — one consolidated document for your audit file.

- **HTML:** https://offendersearch.app/docs/reports
- **Base URL:** https://api.offendersearch.app
- **Authentication:** `X-API-Key` request header
- **OpenAPI:** https://offendersearch.app/openapi.json · https://offendersearch.app/openapi.yaml
- **All documentation as markdown:** https://offendersearch.app/docs.md

## A defensible artifact for your audit file

A verification report is a branded, timestamped PDF of a search you already ran — showing every matching offender and every field on file (photos included), with a source citation on every record. It is your report of public-record data, clearly labeled as Offendersearch output; it does not reproduce, mirror, or impersonate any government website. It is a separate, callable endpoint any valid key can use — there is no per-key entitlement — billed at $0.02 per document.

Request one by passing the `searchId` of a prior `/v1/search` call — up to 7 days afterward — plus, optionally, the `viewerName` and `viewerEmail` of whoever is viewing it. Because the search call was already billed, the report meters only the +$0.02 PDF. The response is a single consolidated PDF for the whole search, with a source-attribution section and the report id in the `X-Report-Id` header.

The document contains: the search criteria verbatim and when the search ran; every matching record with every field on file, including photos and the labelled `matchState`; a source-attribution section citing the publishing jurisdiction for each record; the viewer identity and stated purpose where you supplied them; the report id; and a legal disclaimer.

**The report is a snapshot of one search, not a live query.** It renders the result set of the `searchId` you name, so the completeness the search reported is the completeness the document reflects.

## POST /v1/report — Verification report

A branded, timestamped PDF report of your FULL search results with a source citation on every record — a defensible artifact for your audit file. One consolidated document per search: your report of public-record data, clearly labeled as Offendersearch output; it does not reproduce, mirror, or impersonate any government website.

**Authentication:** `X-API-Key` header.

Pass the `searchId` of a search you already ran — up to **7 days** afterward — and you get back **one consolidated PDF** covering that entire result set, never a separate document per source. A one-shot mode is also supported: send an inline `query` instead of a `searchId` and the endpoint runs the search itself, which meters a search call **as well as** the PDF.

The report captures who viewed it (the optional `viewerName` / `requesterName`) and when, the search criteria, each matching offender, and a **source-attribution** section that cites the source of the data — plus a legal disclaimer. It is available to every account and billed at $0.02 per document; because the underlying search was already billed, the `searchId` path meters only the PDF. Omit the call and there is no extra charge.

The response is `application/pdf`, delivered as a file attachment. The generated report id is returned in the `X-Report-Id` header and printed on the document.

### What you can do

- **One consolidated document.** A single PDF for the whole search — not one document per source.
- **Full source attribution.** Cites the source of every record, with a citation on each.
- **Names the viewer.** viewerName / requesterName, plus optional viewerEmail, purpose and reference, are printed on the report for your audit file. All are optional — the viewer identity is a record, not an access gate.
- **Audit-ready & clearly labeled.** Clearly labeled as Offendersearch output and carries a legal disclaimer; it does not reproduce or impersonate any government site.

### Body

Send a searchId (the normal path), or — in the legacy one-shot mode — every field POST /v1/search accepts (query, jurisdictions, freshness, locationScoped, …). Supply one or the other; neither is a 422.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `searchId` | `string` | optional | The id returned by a prior POST /v1/search or /v1/searches call, up to 7 days old. This is the normal path and it bills only the PDF. A searchId that is unknown, older than 7 days, or belongs to another account is a 404/422. |
| `viewerName` | `string` | optional | Optional. Who is viewing the report; printed at the top of the PDF. requesterName is accepted as an alias. |
| `viewerEmail` | `string` | optional | Optional email of the viewer. Printed on the PDF. |
| `purpose` | `string` | optional | Optional stated purpose for the lookup. Printed on the PDF. |
| `reference` | `string` | optional | Optional caller reference / case id. Printed on the PDF. |

### Request

**cURL**

```bash
curl -X POST https://api.offendersearch.app/v1/report \
  -H "X-API-Key: $OFFENDERSEARCH_KEY" \
  -H "Content-Type: application/json" \
  -o report.pdf -D - \
  -d '{
    "searchId": "srch_9f2c1a7b3e4d",
    "viewerName": "Jane Doe, ACME HR",
    "purpose": "Volunteer background screening"
  }'
# -o writes the PDF to report.pdf; -D - prints the response headers,
# including X-Report-Id, to stdout.
```

**Node**

```javascript
import { writeFileSync } from "node:fs";

const res = await fetch("https://api.offendersearch.app/v1/report", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.OFFENDERSEARCH_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    searchId: "srch_9f2c1a7b3e4d",            // id of a search you already ran
    viewerName: "Jane Doe, ACME HR",          // optional — printed on the PDF
    purpose: "Volunteer background screening", // optional
  }),
});

const reportId = res.headers.get("X-Report-Id");
writeFileSync(`${reportId}.pdf`, Buffer.from(await res.arrayBuffer()));
console.log("saved consolidated report", reportId);
```

**Python**

```python
import os, requests

resp = requests.post(
    "https://api.offendersearch.app/v1/report",
    headers={"X-API-Key": os.environ["OFFENDERSEARCH_KEY"]},
    json={
        "searchId": "srch_9f2c1a7b3e4d",              # id of a search you already ran
        "viewerName": "Jane Doe, ACME HR",            # optional — printed on the PDF
        "purpose": "Volunteer background screening",  # optional
    },
)
report_id = resp.headers["X-Report-Id"]
with open(f"{report_id}.pdf", "wb") as f:            # response body is the PDF
    f.write(resp.content)
print("saved consolidated report", report_id)
```

### Response

```json
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="offendersearch-verification-rpt_9f2c1a7b.pdf"
X-Report-Id: rpt_9f2c1a7b

%PDF-1.7 …(binary PDF body: cover, search criteria, matching
records, a source-attribution section, and
the legal disclaimer)…
```

Returns application/pdf as a file attachment; the report id is in the X-Report-Id header. 401 for a missing/invalid key or session; 404 when the searchId is unknown on this account; 422 when neither a searchId nor a query was supplied, when the search is older than the 7-day retention window, or when the query is invalid (e.g. faceId).

---

## Related

- Previous: [The Record object](https://offendersearch.app/docs/record-object.md)
- Next: [Migrating from another provider](https://offendersearch.app/docs/migration.md)
- Index: [Offendersearch API documentation](https://offendersearch.app/docs.md)
