Sex Offender API sandbox & test keys
A test key, the sandbox base URL, rate limits, and fixed test names for search, batch, compat, records, reports and clearances. Never billed.
Sandboxhttps://sandbox.offendersearch.appLivehttps://api.offendersearch.appAPI sandbox test keys: create one in the dashboard
The sandbox is a separate server with the same endpoints as the live API. This page covers the Sex Offender API: search, batch, stored searches, the offenders.io-compatible endpoint, records, reports and clearances. It answers from a fixed set of made-up people, so every request returns the same result every time, and nothing you send is billed. Build and test your whole integration against it, then switch two settings to go live.
- In the dashboard, open Developers → API keys.
- Choose Create test key. Test keys are for business accounts and need no subscription.
- Copy the key. Test keys begin
os_test_. Like a live key, the full secret is shown once, so put it in your secrets store straight away.
One test key works on every API’s sandbox. Each key in the list is labelled Test · Sandbox or Live, with the base URL it works on. Send it in the same X-API-Key header the live API uses. An account holds up to 3 active test keys and can create 10 a day. A revoked test key stops working on the sandbox within a few minutes.
Sandbox base URL and test keys vs live keys
| Sandbox | Production | |
|---|---|---|
| Base URL | https://sandbox.offendersearch.app | https://api.offendersearch.app |
| Key prefix | os_test_ | os_live_ |
| Data | The fixed test people listed below | 58 sex offender registries |
| Billing | Never billed, never recorded to usage | Your plan’s prices |
sandbox field | true on every response | Absent |
X-Offendersearch-Environment | sandbox on every response | Absent |
Each key works on its own server only, so a mixed-up configuration is caught on the first request rather than after a release. A test key sent to the live API, or a live key sent to the sandbox, is refused with 401 and a detail message that says so:
{
"detail": "This is a test key (os_test_…). Test keys work only on the sandbox at https://sandbox.offendersearch.app, which answers with sample data. To search real records, send a live key (os_live_…) to https://api.offendersearch.app."
}{
"detail": "This is a live key. The sandbox at https://sandbox.offendersearch.app accepts test keys (os_test_…) only — create one in the dashboard under Developers → API keys. Send live keys to https://api.offendersearch.app."
}A revoked test key gets 401 with: “This test key has been revoked. Create a new test key in the dashboard under Developers → API keys.”
Sandbox response format: identical to live, never billed
Every sandbox endpoint takes the same request body and returns the same response shape as its live counterpart, produced by the same serializers: the same envelope, the same Record object, the same matchState, matchConfidence, matchBasis and matchDetail. Code that parses a sandbox response parses a live one. Two things are added so a sandbox answer is never mistaken for a real screening: "sandbox": true in the body and the X-Offendersearch-Environment: sandbox header.
HTTP/1.1 200 OK
X-Offendersearch-Environment: sandbox
{
"sandbox": true,
"searchId": "srch_…",
"status": "complete",
"counts": { "records": 1, … },
"records": [
{ "recordId": "rec_…",
"personRef": "prs_…",
"name": { "first": "Exact", "middle": "Sample", "last": "Match", … },
"dob": "1980-01-01",
"matchState": "dob_match",
"matchConfidence": 0.9,
"registrationState": "OH",
"images": [ { "url": "https://…" } ],
… }
]
}- Never billed. Nothing on the sandbox is billed or recorded to your usage.
- Names match as a pair.
firstNameandlastNameare matched together, ignoring case. Any other name returns a complete answer with zero records. - Dates of birth behave as in production. Send a test person’s
dobexactly as listed; a differentdobcontradicts the record and returns no match, and omitting it returns the person at name-only confidence. - Filters behave as in production. A
state,cityorzipcodereturns a test person only when it matches their registry state or one of their addresses, and a malformed request gets the same422it would in production. - Test data is temporary. Searches, stored results, clearances, monitors and FCRA orders you create in the sandbox are kept for testing and may be reset.
The test people are invented, with sample addresses and placeholder photos marked SAMPLE. They are not real registrants, and their records must never be shown to anyone as real.
Sandbox rate limits
Rate limits keep the sandbox fast for everyone. They apply only to the sandbox, and to every API on it together.
| Limit | Value |
|---|---|
| Requests per test key, per minute | 60 |
| Requests per test key, per day | 2,000 |
| Requests per IP address, per minute | 120 |
| Active test keys per account | 3 |
| Test keys created per account, per day | 10 |
Past a request limit the sandbox answers 429 with a Retry-After header giving the seconds until the window resets. Wait that long and send the request again.
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-Offendersearch-Environment: sandbox
{
"detail": "Sandbox rate limit reached: 60 requests a minute for this test key. Retry after 23s. The sandbox allows 60 requests a minute and 2000 a day per test key, and 120 a minute per IP address.",
"sandbox": true
}Sex offender search test names
Send these to POST /v1/search on the sandbox. Each one returns the same answer every time. The Desk state column is what the mapping in the front-desk visitor screening guide produces for that answer. The same names work on POST /v1/batch, POST /v1/searches and the offenders.io-compatible endpoint, and a returned recordId opens with GET /v1/records/{recordId}.
| Send | What comes back | Desk state |
|---|---|---|
firstName: Clear lastName: Visitor | Clear visitor. No match: a complete answer with zero records. | Clear |
firstName: Exact lastName: Match dob: 1980-01-01 | Exact match, date of birth verified. One strong match: DOB-verified (matchState dob_match), high confidence, photo, offense, registry state and two addresses. | Match |
firstName: Exact lastName: Match | Exact match, no date of birth sent. The same person, matched on name alone: matchState is null because no date of birth was sent to verify. | Review |
firstName: Exact lastName: Match dob: 1990-05-05 | Exact match name, different date of birth. No match: the registry's date of birth contradicts the one sent. | Clear |
firstName: Name lastName: Only | Name only — possible matches. Three possible matches in three states. None of the registries publishes a date of birth, so the name is the only evidence (medium confidence). Sending a dob returns the same three with matchState no_dob_age_year and unverified true. | Review |
firstName: Alias lastName: Match | Matched through an alias. One match whose legal name is different (Jordan Sample Placeholder): matchedName.type is alias, matchBasis carries alias:exact. | Review |
firstName: Out lastName: State state: TX | Registered in another state. One match living in Texas but registered by Oklahoma's registry: registrationState OK, addressStates [TX]. | Review |
firstName: Multi lastName: State | One person on two registries. One record merged from two registries (Florida and Georgia): sources[] lists both. | Review |
firstName: Homeless lastName: Registrant | Homeless registrant. One match with housingStatus homeless. | Review |
curl -X POST "https://sandbox.offendersearch.app/v1/search" \
-H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {
"firstName": "Exact",
"lastName": "Match",
"dob": "1980-01-01"
}
}'In a batch, each row gets the same answer it gets from POST /v1/search, in input order.
curl -X POST "https://sandbox.offendersearch.app/v1/batch" \
-H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"firstName": "Clear",
"lastName": "Visitor"
},
{
"firstName": "Exact",
"lastName": "Match",
"dob": "1980-01-01"
},
{
"firstName": "Exact",
"lastName": "Match"
}
]'Clearances in the API sandbox
All four clearance endpoints run on the sandbox against your sandbox searches. Search a test name with a subjectId, take the searchId and a returned personRef, and POST /v1/clearances with verdict: "not_this_person". The next sandbox search with the same subjectId and clientId lists that person in cleared[] instead of records[], exactly as live. Name Only is a good subject: it returns three people, so you can clear one and keep two.
curl -X POST "https://sandbox.offendersearch.app/v1/search" \
-H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {
"firstName": "Name",
"lastName": "Only"
},
"subjectId": "visitor-1042",
"clientId": "school-3"
}'Other sandbox endpoints: reports, live evidence and catalogues
The rest of the Sex Offender API runs on the sandbox too, with the same paths and shapes as live. The test names above apply wherever a name is searched.
| Send | What comes back |
|---|---|
| POST /v1/report {"searchId": "<a sandbox search id>"} (or an inline query) | Verification report. The production verification PDF (application/pdf, X-Report-Id header) for the sample people that search returned, without photographs. Never billed. |
| POST /v1/search with "proof": {"registries": ["OH"]}, or POST /v1/searches/{id}/proof | Proof documents. A ProofBundle: status ready, one document per registry at /v1/proof-docs/{token}, rendered by the production renderer. billedDocuments is 0: the sandbox bills nothing. |
| POST /v1/search with "live": {"jurisdictions": ["OH"], "evidence": "pdf"} | Live evidence documents. 202 {searchId: evs_…, status: pending, mode: async, registries, pollUrl}. The first poll of GET /v1/searches/{evs_…} is complete: the search plus evidence[] with one complete SAMPLE PDF per registry (inline pdfBase64 and a downloadUrl). Nothing billed: billed false, chargeUsd 0. |
| GET /v1/sources (no key) | Registry catalogue. The production catalogue of 58 registries. health is null: the sandbox has no ingest. |
| GET /v1/status, GET /v1/sandbox/fixtures (no key) | Sandbox status. Environment, base URLs, key prefix, rate limits; and this file's scenarios. |
Sandbox API examples in cURL, Node and Python
The date-of-birth-verified test person, called three ways. Export your test key as OFFENDERSEARCH_TEST_KEY first.
curl -X POST "https://sandbox.offendersearch.app/v1/search" \
-H "X-API-Key: $OFFENDERSEARCH_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {
"firstName": "Exact",
"lastName": "Match",
"dob": "1980-01-01"
}
}'Postman collection for the OffenderSearch sandbox
One collection covers every API’s sandbox, with a folder per API, ready to import into Postman or Insomnia. The Sex Offender API folder has one request for every scenario on this page. Set {{apiKey}} to your test key; {{baseUrl}} is preset to the sandbox. A request that needs an id from an earlier response uses a variable for it: {{searchId}}.
Download the sandbox collection (JSON)
Postman: Import, then drop the file. Insomnia: Import, then From file.
Sandbox test keys for the criminal, monitoring, Map and FCRA APIs
Each API’s docs have their own sandbox page, with that API’s test data, calls and Postman folder. The same os_test_ key works on all of them.
Move from the API sandbox to production
The sandbox and the live API differ only in the base URL and the key. Keep both in configuration, not in code, and going live is a configuration change:
# Sandbox
OFFENDERSEARCH_BASE=https://sandbox.offendersearch.app
OFFENDERSEARCH_KEY=os_test_…
# Production — change these two values and nothing else
OFFENDERSEARCH_BASE=https://api.offendersearch.app
OFFENDERSEARCH_KEY=os_live_…- Create a live key on the same Developers → API keys page.
- Remove any branch that reads
sandbox. The field does not exist on live. - Live answers are real people. Read Matching & confidence and Date of birth before you decide what your interface shows for each
matchState. - Live calls are billed; see pricing.
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