Test mode is a parallel data plane that lets you exercise every endpoint and provider scenario without touching production data or paying real-money provider fees. It is scoped by API key — test keys can only see and create test records, and live keys can only see and create live records. The two planes never overlap.
Use test mode while you build out your integration, run end-to-end tests in CI, and demo the API to stakeholders. Switch to live keys for production traffic.
API keys are managed from the Developer Settings page in the Checkr Tenant dashboard. Each organization can mint two kinds of keys:
- Live keys — prefixed
ckr_sk_live_. Used for production traffic. Records created with a live key are real, billable, and route to real provider integrations. - Test keys — prefixed
ckr_sk_test_. Used for development and integration testing. Records created with a test key are inert, unbilled, and route to canned provider responses (see Canned Provider Scenarios below).
The full token value is shown once at creation time and cannot be retrieved later — capture it then. Tokens are sent on every request as a bearer credential:
Authorization: Bearer ckr_sk_test_<...>Order and Report responses carry a boolean live_mode field that confirms which plane the record was created in. For Applicants and Properties the mode is encoded in the resource ID (see below) rather than as a separate field.
{
"id": "ord_test_TUyYsLnyTbG3xv9hONJF7w",
"live_mode": false,
"status": "pending",
...
}Resource IDs also encode the mode: test-mode IDs carry a _test_ infix between the resource prefix and the suffix (e.g. ord_test_…, rp_test_…), while live-mode IDs have no infix (e.g. ord_…, rp_…). Either form is accepted on read endpoints, but a test key cannot fetch a live ID and vice versa — the response is 404 not_found_error (see Errors).
Reads are automatically scoped to the mode of the calling key:
- A list or lookup with a test key returns only test-mode records.
- A list or lookup with a live key returns only live-mode records.
- Cross-mode lookups return
404 not_found_error. The response is identical to a record that does not exist, to avoid leaking the existence of records from the other plane.
Orders created with a test API key route to canned provider responses instead of real screening providers. The applicant fields on the order determine which scenario fires; partial matches are treated as a miss and return the clean scenario for every product, so a typo cannot accidentally leak a hit.
A scenario fires when first name, last name, date of birth, and SSN all match one of the profiles below. All test profiles share the same date of birth: 1996-04-27.
Submit first_name and last_name on the applicant — for example "first_name": "Herbert" and "last_name": "Humphrey" — along with dob and ssn. Legacy full_name input is still accepted during the current API version, but not in the same request as first_name or last_name.
| First | Last | DOB | SSN | Criminal History | Credit Report | Eviction History | Income Verification | Sex Offender Registry | Global Watchlist |
|---|---|---|---|---|---|---|---|---|---|
| Herbert | Humphrey | 1996-04-27 | 111-11-1111 | consider | clear | clear | consistent_income | clear | clear |
| Madelyn | Webster | 1996-04-27 | 222-22-2222 | clear | consider | clear | variable_income | clear | clear |
| Norma | Davies | 1996-04-27 | 333-33-3333 | clear | clear | consider | high_assets | clear | clear |
| Tim | Watkins | 1996-04-27 | 444-44-4444 | consider | consider | consider | low_assets | consider | consider |
| Hudson† | Green | 1996-04-27 | 555-55-5555 | clear | clear | clear | consistent_income | clear | clear |
| any other tuple | clear | clear | clear | consistent_income | clear | clear |
† Hudson Green does not circumvent the applicant experience — see Applicant Experience in Test Mode.
Notes:
- The SSNs above are reserved test ranges and the names do not collide with production records, so the values are inert.
- Submitting an order with any other applicant returns the clean scenario for every product. This is the right behavior for golden-path tests where you do not need a flagged result.
- For income verification, the label in the table identifies which canned report shape is returned (income streams, account balances, NSF history). See the income-verification schema for the full field list. Bank-connection setup is bypassed entirely for test-mode orders.
The tuples above all return bank-sourced income. To exercise the document path instead, order income verification for Ingrid Vance, DOB 1996-04-27, with one of two SSNs:
| First | Last | DOB | SSN | Document risk |
|---|---|---|---|---|
| Ingrid | Vance | 1996-04-27 | 666-66-6666 | all three documents low |
| Ingrid | Vance | 1996-04-27 | 666-66-6667 | paystub medium, W-2 high, bank statement low |
Submitting the order attaches a bank statement, a paystub and a W-2 as though the applicant uploaded them in the application flow. income_verification comes back with a verification_method of document, the three entries in documents, and income data extracted from them.
The two tuples differ only in document risk, and the difference is visible in the reported income: a document assessed high is excluded, so the second tuple's W-2 contributes nothing and total_past_12_months_estimated_gross_cents comes back null, while its medium paystub still counts.
Both document endpoints work against these test-mode orders. Each entry in income_verification.documents carries a download_url pointing at GET /reports/{id}/documents/{document_id}/download, which returns that document as a real PDF — a sample paystub, W-2 or bank statement made out to the test applicant. GET /reports/{id}/documents/zip returns a ZIP holding all three in its income_documents/ folder.
Add add_on_products: ["identity_verification"] to the order and the same archive also carries an identity_verification/ folder. Those images are fixed placeholder files rather than captured documents, so use them to verify your handling of the archive's structure, not to check image content.
Identity Verification is an add-on product, not bundled into any package. It runs only when the order is created with add_on_products: ["identity_verification"]. Outcomes are selected by a subset of profiles from the table above — matching one of the rows below by first name, last name, DOB, and SSN triggers the listed consider result; any other applicant tuple returns clear.
| First | Last | DOB | SSN | Identity Verification |
|---|---|---|---|---|
| Norma | Davies | 1996-04-27 | 333-33-3333 | consider — doc_expired |
| Tim | Watkins | 1996-04-27 | 444-44-4444 | consider — selfie_mismatch, name_mismatch |
The categories shown correspond to entries in the consider_reasons array on the report item. See the identity-verification schema for the full set of possible categories.
Example request that triggers the doc_expired IDV outcome:
{
"order": {
"package": "starter",
"add_on_products": ["identity_verification"],
"applicant": {
"first_name": "Norma",
"last_name": "Davies",
"email": "norma@example.com",
"dob": "1996-04-27",
"ssn": "333-33-3333"
},
"property": { "...": "..." }
}
}By default, test mode circumvents the applicant experience so that you receive the test report immediately. No email or SMS communication is sent to the test applicant and the applicant experience is skipped.
If you would like to see the applicant experience, submit the order with the Hudson Green tuple from the table above. You will receive an application link at the email provided, and the create-order response includes application_url (other test profiles return null for that field because they skip the apply flow).
If the selected package includes identity or income verifications, provider flows are bypassed. Buttons to simulate ID upload and/or bank connection appear in their place.
Webhook endpoints are also bound to a single mode at registration time and only receive events from that mode:
- A webhook endpoint registered with a test key receives events for test-mode resources only.
- A webhook endpoint registered with a live key receives events for live-mode resources only.
Event payloads use the same shape across modes. Webhook events carry only the affected resource's id in data (not an embedded object), so the plane is identifiable from the ID infix — rp_test_… / ord_test_… for test-mode events, no infix for live-mode.
Test mode is supported across the public API: