> ## 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.

# Quickstart

> Get started with the SNH AI Public Records API in 5 minutes

## Prerequisites

* API key from [Account Setup](/account-setup)
* cURL or your preferred HTTP client
* Basic understanding of REST APIs

## Step 1: Configure Environment

Set your base URL and API key as environment variables so every command below is copy-pasteable:

<CodeGroup>
  ```bash bash theme={null}
  export PR_API_BASE=https://cra.pr.snh-ai.com
  export PR_API_KEY="eval-api-key-<your-unique-key>"
  ```

  ```powershell PowerShell theme={null}
  $env:PR_API_BASE = "https://cra.pr.snh-ai.com"
  $env:PR_API_KEY = "eval-api-key-<your-unique-key>"
  ```
</CodeGroup>

## Step 2: Verify Connectivity

Confirm the API is up before proceeding:

<CodeGroup>
  ```bash cURL theme={null}
  curl "$PR_API_BASE/health"
  ```

  ```python Python theme={null}
  import requests, os

  base = os.environ["PR_API_BASE"]
  resp = requests.get(f"{base}/health")
  print(resp.json())
  ```

  ```javascript JavaScript theme={null}
  const base = process.env.PR_API_BASE;

  const resp = await fetch(`${base}/health`);
  console.log(await resp.json());
  ```
</CodeGroup>

**Expected response:**

```json theme={null}
{
  "status": "healthy",
  "service": "eval-framework",
  "services": {
    "xml_transformer": true,
    "compliance_engine": true
  }
}
```

## Step 3: Get Auth Token

Exchange your API key for a JWT token (valid for 2 hours). See [Authentication](/authentication) for the full guide.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$PR_API_BASE/auth/token" \
    -H "X-API-Key: $PR_API_KEY" \
    -H "Content-Type: application/json"
  ```

  ```python Python theme={null}
  import requests, os

  base = os.environ["PR_API_BASE"]
  api_key = os.environ["PR_API_KEY"]

  resp = requests.post(
      f"{base}/auth/token",
      headers={"X-API-Key": api_key}
  )
  token = resp.json()["access_token"]
  print(f"Token: {token[:20]}...")
  ```

  ```javascript JavaScript theme={null}
  const base = process.env.PR_API_BASE;
  const apiKey = process.env.PR_API_KEY;

  const resp = await fetch(`${base}/auth/token`, {
    method: "POST",
    headers: { "X-API-Key": apiKey }
  });
  const { access_token } = await resp.json();
  console.log(`Token: ${access_token.slice(0, 20)}...`);
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 7200
}
```

Save the `access_token` — you'll use it in the next step:

```bash theme={null}
export PR_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

## Step 4: Evaluate a Record

Save the following JSON as `record.json`:

```json record.json theme={null}
{
  "record": {
    "xml": "<ScreeningResults><login><account>05022022</account><username>test</username></login><postResults order=\"12345\"><case><case_number>MJ-05003-TR-0006023-2020</case_number><offense_date>20200310</offense_date><jurisdiction_state>PA</jurisdiction_state><chargeinfo><charge>DRIVING WHILE OPERATOR PRIVILEGES SUSPENDED</charge><disposition>GUILTY</disposition></chargeinfo></case></postResults></ScreeningResults>",
    "search_id": "test-123",
    "search_date": "2025-04-30",
    "order_id": "12345",
    "order_number": "12345.1",
    "cases": [
      { "court_search_id": "CS40929433A", "offense_id": "34789896" }
    ],
    "applicant_state": "CA",
    "candidate_info": {
      "first_name": "John",
      "last_name": "Doe",
      "date_of_birth": "1990-05-15"
    }
  }
}
```

Then submit it:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$PR_API_BASE/evaluate" \
    -H "Authorization: Bearer $PR_TOKEN" \
    -H "Content-Type: application/json" \
    --data @record.json
  ```

  ```python Python theme={null}
  import requests, json, os

  base = os.environ["PR_API_BASE"]
  token = os.environ["PR_TOKEN"]

  with open("record.json") as f:
      payload = json.load(f)

  resp = requests.post(
      f"{base}/evaluate",
      headers={
          "Authorization": f"Bearer {token}",
          "Content-Type": "application/json"
      },
      json=payload
  )
  result = resp.json()
  decision = result["data"]["decision"]
  print(f"Search queue: {decision['search_queue']}")
  for court in decision["court_decisions"]:
      for case in court["case_decisions"]:
          for offense in case["offenses"]:
              print(offense["offense_id"], offense["charge_decision"], offense["routing"]["queue"])
  ```

  ```javascript JavaScript theme={null}
  import { readFileSync } from "fs";

  const base = process.env.PR_API_BASE;
  const token = process.env.PR_TOKEN;

  const payload = JSON.parse(readFileSync("record.json", "utf-8"));

  const resp = await fetch(`${base}/evaluate`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(payload)
  });
  const result = await resp.json();
  const decision = result.data.decision;
  console.log(`Search queue: ${decision.search_queue}`);
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "data": {
    "search_id": "test-123",
    "correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "success",
    "errors": [],
    "decision": {
      "search_id": "test-123",
      "decision_date": "2026-05-11T14:30:19Z",
      "record_decision": "NOT_REPORTABLE",
      "search_queue": "Automation",
      "order_id": "",
      "court_decisions": [
        {
          "court_search_id": "TBD",
          "court_queue": "Automation",
          "case_decisions": [
            {
              "case_number": "MJ-05003-TR-0006023-2020",
              "case_queue": "Automation",
              "jurisdiction_state": "PA",
              "id_match": {
                "is_match": true,
                "match_score": 0.85,
                "name_score": 1,
                "dob_score": 1,
                "ssn_score": 0,
                "address_score": 0
              },
              "offenses": [
                {
                  "offense_id": "4628347",
                  "charge": "DRIVING WHILE OPERATOR PRIVILEGES SUSPENDED",
                  "charge_decision": "NOT_REPORTABLE",
                  "rationale": "The traffic violations are not reportable, unless it's a felony.",
                  "type": "SUMMARY",
                  "disposition": "GUILTY",
                  "needs_human_review": false,
                  "cited_rules": ["GENERAL_TRAFFIC_NON_REPORT", "EXCLUSION_FILTER_CHARGE"],
                  "citations": [],
                  "routing": {
                    "queue": "Automation",
                    "is_automatable": true,
                    "identity_level": "High",
                    "identity_score": 0.85
                  }
                }
              ]
            }
          ]
        }
      ]
    },
    "timing": {
      "xml_transformer_ms": 1200.5,
      "compliance_ms": 330.7,
      "total_ms": 1850.3
    }
  },
  "meta": {
    "api_version": "2.0.0",
    "process_time_ms": 1855,
    "correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
```

## Step 5: Understand the Response

Every response is wrapped in a `{ success, data, meta }` envelope. The evaluation result is at `data.decision`:

| Level        | Path                                              | Description                                                              |
| ------------ | ------------------------------------------------- | ------------------------------------------------------------------------ |
| **Envelope** | `success`, `data`, `meta`                         | Standard wrapper with status and timing                                  |
| **Search**   | `data.decision.record_decision`                   | Top-level reportability: `REPORTABLE`, `NOT_REPORTABLE`, `MANUAL_REVIEW` |
| **Search**   | `data.decision.search_queue`                      | Top-level routing queue: `Automation`, `Auditor`, `Insufficient Data`    |
| **Court**    | `data.decision.court_decisions[].court_decision`  | Per-court reportability                                                  |
| **Court**    | `data.decision.court_decisions[].court_queue`     | Per-court routing queue                                                  |
| **Case**     | `...case_decisions[].case_decision`               | Per-case reportability                                                   |
| **Case**     | `...case_decisions[].case_queue`                  | Per-case routing queue                                                   |
| **Charge**   | `...offenses[].charge_decision` + `routing.queue` | Per-charge reportability and routing                                     |

**Queue rollup priority:** `Insufficient Data` > `Auditor` > `Automation`. A single charge that lacks data is enough to mark the whole case (and therefore court and search) as `Insufficient Data`.

When the source record has data-quality issues (e.g., missing SSN or disposition), the response also includes a structured `validation` object alongside `decision`. When the data is clean, `validation` is omitted entirely.

## Next Steps

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/api-reference/overview">
    Explore all available endpoints and options
  </Card>

  <Card title="Code Examples" icon="book" href="/examples">
    Working examples in Python, JavaScript, and cURL
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/error-handling">
    Retry logic, failure handling, and troubleshooting
  </Card>

  <Card title="Environments" icon="server" href="/environments">
    Production, staging, and dev environment URLs
  </Card>
</CardGroup>

## Need Help?

<snippet file="snippets/support.mdx" />
