Background check SDKs: Python, Node.js and a CLI.
Official clients for the background check API: pip install offendersearch, npm install @offendersearch/sdk, and the offendersearch command. One method per documented endpoint, typed responses and errors, retries that honour Retry-After, a webhook verifier, and a sandbox key that makes every example free to run.
pip install offendersearch
from offendersearch import OffenderSearch
client = OffenderSearch() # OFFENDERSEARCH_API_KEY; os_test_ → sandbox
r = client.search({"firstName": "Jordan", "lastName": "Rivera", "dob": "1988-04-12"})
print(r["status"], r["counts"]["records"]) # complete 0Background check SDK — Two packages and a CLI, one API surface
offendersearch (PyPI)
Python 3.9+, zero dependencies, typed TypedDict responses, typed exceptions, a transport= seam for httpx or tests. Tutorial: background check API in Python.
@offendersearch/sdk (npm)
Node 18+, ESM and CommonJS, bundled TypeScript types, zero runtime dependencies, fetch-based with an injectable fetch. Tutorial: background check API in Node.js.
offendersearch (CLI)
Ships in the npm package: search, criminal, record, monitors, verify-webhook. JSON out, so it composes with jq.
client.search(query, …) POST /v1/search client.criminal.search(query, …) POST /v1/criminal/search
client.search_async / searchAsync POST /v1/searches client.criminal.search_pages every page
client.get_search / getSearch GET /v1/searches/{id} client.criminal.batch POST /v1/criminal/batch
client.wait poll until complete client.criminal.get_record GET /v1/criminal/records/{id}
client.batch POST /v1/batch client.criminal.sources GET /v1/criminal/sources
client.get_record / getRecord GET /v1/records/{id} client.monitors.create POST /v1/monitors
client.report POST /v1/report (PDF) client.monitors.alerts GET /v1/monitors/{id}/alerts
client.evidence_pdf / evidencePdf live evidence capture (PDF) client.map.viewport GET /v1/map/viewport
client.clearances.* /v1/clearances client.fcra.* /v1/fcra/* (approved partners)
webhooks.verify / verifyWebhook X-Offendersearch-Signature typed errors 401 402 403 404 422 429 504 5xxBoth packages cover every documented path in the API reference — registry search, criminal records, batch, async, reports and evidence, clearances, monitors, the Map API and the FCRA orders API — and a test in the repository fails when the contract gains a path neither SDK has.
pip install offendersearch · npm install @offendersearch/sdk — Install and the first call
Both packages read OFFENDERSEARCH_API_KEY. A key that starts with os_test_ sends every request to the sandbox, where fixed sample people answer the same way every time and nothing is billed; a live key goes to the live host. The hero above is the whole first call in each language — the synthetic subject Jordan Rivera, 1988-04-12 returns a complete answer with zero records, which is the clear case you want to see first. Create a key to run it; 25 live calls are free, no card.
Typed background check responses — matchState, counts and record types in your editor
The two fields that drive every decision are typed in both languages: matchState on each record (dob_match, year_match, age_match, or null when you sent no date) and counts.sourcesIncomplete on the response, which is the one number that means something may be missing. Criminal records carry recordType — court_case, jail_booking, doc_inmate, warrant, healthcare_exclusion — so a booking is never read as a conviction.
| Need | Python | Node.js |
|---|---|---|
| One registry search | client.search(query) | client.search(query) |
| Criminal records, paged | client.criminal.search_pages(query) | for await (const p of client.criminal.searchPages(query)) |
| Async + wait | client.search_async(…); client.wait(id) | client.searchAsync(…); await client.wait(id) |
| Batch of 1,000 | client.batch(rows) | client.batch(rows) |
| Report PDF | client.report(search_id=…) → bytes | client.report({ searchId }) → Buffer |
| Monitor + alerts | client.monitors.create(…); .alerts(id) | client.monitors.create(…); .alerts(id) |
Field meanings: the record object and the criminal record object; match states in the matching reference.
Verify background check webhooks — One signature scheme, one function
Monitor alerts and FCRA events arrive with X-Offendersearch-Signature: t=<unix>,v1=<hex>, an HMAC-SHA256 over "<t>.<body>" with the secret issued when you created the monitor or endpoint. Both SDKs verify it in constant time with a five-minute replay window, on the raw body bytes.
from offendersearch import webhooks
ok = webhooks.verify(secret, request.headers["X-Offendersearch-Signature"], raw_body)Try it without writing code: the webhook tester signs sample events and checks your verification. The scheme is explained in webhook example and API signature.
Background check API errors in the SDKs — Typed, with Retry-After honoured
Every non-2xx answer becomes a typed error with the HTTP status, the API’s machine code when it sent one, and the human message. Both clients retry 429, 502, 503 and 504 (and a dropped connection) up to three times, waiting the Retry-After seconds the API names, with exponential backoff otherwise. Nothing else is retried: a 422 is a contract — the request was refused with a sentence you can show a user — and a 401 is yours to fix.
| Class | Status | Meaning |
|---|---|---|
AuthenticationError | 401 | Missing or invalid X-API-Key |
PaymentRequiredError | 402 | Billing or a subscription is needed |
ForbiddenError | 403 | The key may not do this |
NotFoundError | 404 | No such search, record, monitor or order |
ValidationError | 400 · 413 · 422 | Refused, nothing ran; .code and the field errors say why |
RateLimitError | 429 | Nothing ran or was billed; .retryAfter / .retry_after |
DeadlineError | 504 | A deadline you set was hit, or incomplete_no_results |
ServerError | 5xx | Already retried; .requestId for support |
The catalogue and both error envelopes are in the errors reference and API errors, explained.
Background check SDK sandbox — Free, fixed answers, same shapes as production
The sandbox is a separate host with the same paths and response shapes. It answers from a fixed cast of sample people — Exact Match (1980-01-01) is a DOB-verified registry hit, Felony Record (1975-06-15) a closed felony case, Clear Visitor a clean answer — so your tests are deterministic, your CI runs without a card, and a monitor you create there files its alert at once. Mint up to three os_test_ keys from the dashboard; every scenario is listed on the sandbox reference.
SDK versioning and support — What we promise about the packages
- Semantic versioning. A breaking change to a method signature is a major version; a new endpoint or field is a minor one.
- Both packages release together with one version number, from one repository, with a contract test that fails when the API gains a path neither SDK covers.
- Python 3.9+ and Node 18+ are supported until each runtime’s own end of life.
- No runtime dependencies in either package, so an upgrade never pulls a transitive surprise.
- The API itself is versioned at
/v1; additions are non-breaking and listed in the changelog. - Source is published with the first release under the OffenderSearch organisation; issues and questions go to support@offendersearch.app.
What the background check SDKs do not do
- They do not make a hiring or housing decision FCRA-compliant on their own; those run as orders through FCRA Partner Access, reached via
client.fcraonce approved. - They do not take or trace a Social Security number. Searches are by name, date of birth and place.
- They do not include driving records, drug tests, credit, or education and employment verification — the API is public records: 58 US sex offender registries and criminal court, jail, prison, warrant and exclusion-list records.
- They do not run in a browser or a mobile app. The key stays on your server.
- There is no Go, Ruby, PHP or Java package yet. The API is plain HTTPS and JSON; the Postman collection and the reference cover any language.
Background check SDK questions
Which languages have an official background check SDK?
Do the SDKs cost anything?
Can I use the SDKs with the sandbox?
Do the SDKs support the FCRA orders API?
client.fcra: end users, search plans, orders, scope, reports, receipts, evidence, disputes, invitations, consent documents, branding, adverse action, revisions, monitors, webhook endpoints and events. It works on the sandbox for everyone and on the live host for approved partners.How do the SDKs handle rate limits?
Is there a Go, Ruby, PHP or Java SDK?
Can I generate a client from the OpenAPI spec instead?
/openapi.json and /openapi.yaml; the API reference is rendered from it. The official SDKs add retries, typed errors, pagination and webhook verification on top.Where do I report a bug in an SDK?
Background check SDKs — Install one and run the first search
pip install offendersearch or npm install @offendersearch/sdk, create a key, paste the example. 25 calls are free.