> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pr.snh-ai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How It Works

> Step-by-step walkthrough of how the Public Records service processes criminal records

## The Request Flow

When you submit a criminal record for evaluation, the service processes it through three stages and returns a complete compliance decision in a single API response.

```mermaid theme={null}
flowchart LR
    A["You submit\na criminal record"] --> B["Record is parsed\nand normalized"]
    B --> C["Candidate identity\nis verified"]
    C --> D["Compliance rules\nare applied"]
    D --> E["Decision returned\nin API response"]
```

**Stage 1 — Parse and normalize.** The raw screening data (XML or JSON) is parsed into a structured format. Charge descriptions, dates, and disposition values are standardized so compliance rules can be applied consistently.

**Stage 2 — Verify identity.** The candidate you're screening is compared against the person named in the criminal record. The service checks name, date of birth, SSN, and address to determine whether the record actually belongs to your candidate.

**Stage 3 — Apply compliance rules.** Each charge is evaluated against federal FCRA rules and state-specific laws. The service determines whether the charge is reportable, not reportable, or needs manual review — and assigns a routing recommendation.

All three stages happen behind a single `POST /evaluate` call. The response contains the complete decision.

***

## Orders, Searches, and Actions

Background screening follows a hierarchy: **Orders** contain **Searches**, and each search produces a set of **Actions** (decisions).

```mermaid theme={null}
flowchart TD
    Order["Order\n(order_id: 41115779)"] --> S1["Search 1\n(order_number: 41115779.1)\nCounty Criminal — Harris County, TX"]
    Order --> S2["Search 2\n(order_number: 41115779.2)\nStatewide Criminal — Texas"]
    Order --> S3["Search 3\n(order_number: 41115779.3)\nCounty Criminal — Travis County, TX"]
    S1 --> D1["POST /evaluate → Decision"]
    S2 --> D2["POST /evaluate → Decision"]
    S3 --> D3["POST /evaluate → Decision"]
```

| Concept      | What it is                                                                        | Identifier                   | Example                                           |
| ------------ | --------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------------------- |
| **Order**    | A background check request for one candidate, which may include multiple searches | `order_id`                   | `"41115779"`                                      |
| **Search**   | One criminal record search within an order (e.g., one county, one state)          | `order_number` + `search_id` | `"41115779.1"` / `"76190bc0-..."`                 |
| **Decision** | The compliance evaluation result for one search                                   | Returned in the API response | `REPORTABLE` / `NOT_REPORTABLE` / `MANUAL_REVIEW` |

**Each `POST /evaluate` call evaluates one search.** If an order has three searches (county, statewide, federal), you make three separate API calls. The response for each call is self-contained — it includes the decision for every charge in that search.

***

## What You Send

The service accepts criminal records in two formats. **Mapped JSON works for both initial evaluation and resubmission** (use `submission_type: "resubmit"` with `record_json`).

| Format          | When to use                                                                   | Field                |
| --------------- | ----------------------------------------------------------------------------- | -------------------- |
| **Raw XML**     | Vendor screening XML (typical initial path)                                   | `record.xml`         |
| **Mapped JSON** | Initial JSON-native submission **or** resubmission with corrected/mapped data | `record.record_json` |

Companion fields on `record` (same for both formats):

* **Candidate info** — required with `record_json`; recommended with XML (name, DOB; optional SSN/address)
* **Search metadata** — `search_id`, `search_date`, `order_id`, `order_number`
* **Charge mapping** (`cases[]`, optional) — maps each charge to your court/offense IDs; omit or `[]` to evaluate all charges without the count gate

See [Supported XML Schemas](/xml-schemas) for XML formats, and [Evaluate](/api-reference/endpoints/evaluate) for `record_json`.

***

## What You Get Back

Every response follows the same structure, regardless of whether you submitted XML or JSON:

```mermaid theme={null}
flowchart TD
    Response["API Response"] --> Envelope["Envelope\nsuccess · status · correlation_id"]
    Response --> Decision["Decision\nrecord_decision · search_queue"]
    Response --> Validation["Validation\n(only when data issues exist)"]
    Response --> Timing["Timing\nprocessing time breakdown"]

    Decision --> Courts["Court Decisions"]
    Courts --> Cases["Case Decisions\n+ identity match scores"]
    Cases --> Charges["Charge\ncharge_decision + routing.queue"]
```

### Charge decision and queue

For day-to-day integration, focus on two fields **per charge**:

| Concept             | Field                        | Values                                          | What it means                                         |
| ------------------- | ---------------------------- | ----------------------------------------------- | ----------------------------------------------------- |
| **Charge decision** | `offenses[].charge_decision` | `REPORTABLE`, `NOT_REPORTABLE`, `MANUAL_REVIEW` | Whether this charge can appear on a background report |
| **Queue**           | `offenses[].routing.queue`   | `Automation`, `Auditor`, `Insufficient Data`    | Where work should go next                             |

Common pairing (queue follows the routing matrix; identity match can change the queue):

| Charge decision  | Common queue      | What to do                                                    |
| ---------------- | ----------------- | ------------------------------------------------------------- |
| `NOT_REPORTABLE` | Automation        | Cleared — exclude from the report. No human review needed.    |
| `REPORTABLE`     | Auditor           | Can be reported — route to an auditor for final verification. |
| `MANUAL_REVIEW`  | Insufficient Data | Not enough information — route to a researcher.               |

### Hierarchy (rollup)

The response nests **Record → Courts → Cases → Charges**. Parent levels roll up child **queues**; aggregated `*_decision` labels mirror those queues.

| Level      | Decision field    | Queue field     | What it means                         |
| ---------- | ----------------- | --------------- | ------------------------------------- |
| **Record** | `record_decision` | `search_queue`  | Overall outcome for the entire search |
| **Court**  | `court_decision`  | `court_queue`   | Outcome for all cases in one court    |
| **Case**   | `case_decision`   | `case_queue`    | Outcome for all charges in one case   |
| **Charge** | `charge_decision` | `routing.queue` | Outcome for one individual charge     |

**Queue rollup priority:** `Insufficient Data` > `Auditor` > `Automation`.

### Response status codes

| HTTP Status | `data.status`         | What happened                                                               |
| ----------- | --------------------- | --------------------------------------------------------------------------- |
| **200**     | `success`             | All processing completed — full decision returned                           |
| **206**     | `partial`             | Some processing stages failed, but partial results were still returned      |
| **400**     | —                     | Bad request — missing or invalid fields in your payload                     |
| **422**     | `validation_required` | Your charge mapping (`cases[]`) doesn't match the record — fix and resubmit |
| **500**     | `failed`              | Processing failed entirely — retry with backoff                             |

### Data quality issues

`data.validation` is **only present when the pipeline found data-quality problems** (for example missing disposition, ambiguous charge type, or weak identity fields). Each issue lists the field and why it failed — use that to understand `Insufficient Data` routing.

If there are no data-quality problems, **`validation` is not in the response at all** (not `null`, not `{}` — the key is absent). That means the source data passed those checks; it does not mean every charge is reportable.

***

## End-to-End Example

Typical single-search flow:

```mermaid theme={null}
sequenceDiagram
    participant You
    participant SNH AI

    You->>SNH AI: POST /auth/token (API key)
    SNH AI-->>You: JWT token (expires_in seconds)

    You->>SNH AI: GET /health
    SNH AI-->>You: { status: "healthy" }

    You->>SNH AI: POST /evaluate (XML or record_json + candidate_info)
    SNH AI-->>You: Decision for each charge

    Note over You: Process the decision:<br/>- Auto-clear NOT_REPORTABLE charges<br/>- Route REPORTABLE to auditors<br/>- Route MANUAL_REVIEW to researchers
```

1. **Authenticate** — Exchange your API key for a JWT token (`POST /auth/token`). Use the returned `expires_in` (currently 3600 seconds / 1 hour).
2. **Check health** (optional) — Confirm the service is available (`GET /health`).
3. **Evaluate** — Call `POST /evaluate` with either `record.xml` or `record.record_json`, plus `candidate_info` and search metadata.
4. **Process the decision** — For each charge in the response:
   * `NOT_REPORTABLE` → Automatically exclude from the background report
   * `REPORTABLE` → Send to your auditor queue for final verification
   * `MANUAL_REVIEW` → Send to your researcher queue for investigation
5. **Handle errors** — If a request fails, follow the [Retry Logic](/retry-logic) guidelines.

If your workflow uses multiple searches under one order, repeat step 3 once per search (see [Orders, Searches, and Actions](#orders-searches-and-actions)).

***

## Related

* [Quickstart](/quickstart) — Run your first evaluation in 5 minutes
* [Supported XML Schemas](/xml-schemas) — XML formats accepted by the service
* [API Reference](/api-reference/overview) — Complete endpoint documentation
* [Routing & Queues](/api-reference/routing) — Detailed routing matrix and rollup logic
