Summary and recommendation
Checkr exposes a REST API at https://api.checkr.com/v1 using HTTP Basic Auth - the API key is passed as the username with an empty password.
A critical architectural distinction applies before any integration work begins: the REST API manages candidates (people being screened) and background check reports, while dashboard team member accounts are managed exclusively via SCIM 2.0 at https://api.checkr.com/scim/v2. These are separate surfaces with separate auth contexts and separate data models.
Teams building identity lifecycle automation via an MCP server with ~100 deep IT/identity integrations should route dashboard user provisioning through the SCIM endpoint, not the REST API.
API quick reference
| Has user API | Yes |
| Auth method | HTTP Basic Auth with API key as username, password empty |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: HTTP Basic Auth with API key as username, password empty
Setup steps
- Log in to the Checkr Dashboard.
- Navigate to Account Settings > Developer Settings.
- Generate or copy your API key.
- Use the API key as the HTTP Basic Auth username with an empty password, or pass it as a Bearer token in the Authorization header.
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique identifier for the candidate | auto-generated | immutable | Checkr uses 'candidate' as the primary user/person object |
| first_name | string | Candidate's first name | required | allowed | |
| middle_name | string | Candidate's middle name | optional | allowed | |
| last_name | string | Candidate's last name | required | allowed | |
| string | Candidate's email address | required | allowed | Used to send candidate invitations | |
| phone | string | Candidate's phone number | optional | allowed | |
| dob | string (YYYY-MM-DD) | Date of birth | optional | allowed | Required for some background check packages |
| ssn | string | Social Security Number | optional | not allowed | Sensitive field; masked in responses |
| driver_license_number | string | Driver's license number | optional | allowed | |
| driver_license_state | string | State of driver's license | optional | allowed | |
| zipcode | string | Candidate's ZIP code | optional | allowed | |
| work_locations | array | List of work location objects (city, state, country) | optional | allowed | Used for jurisdiction-specific compliance |
| custom_id | string | Your internal identifier for the candidate | optional | allowed | Useful for mapping to your own user records |
| object | string | Always 'candidate' | auto-set | immutable | |
| uri | string | Resource URI for the candidate | auto-generated | immutable | |
| created_at | string (ISO 8601) | Timestamp of candidate creation | auto-generated | immutable | |
| updated_at | string (ISO 8601) | Timestamp of last update | auto-generated | auto-updated |
Core endpoints
Create Candidate
- Method: POST
- URL:
https://api.checkr.com/v1/candidates - Watch out for: Duplicate candidates may be created if the same email is submitted multiple times; Checkr does not deduplicate by email automatically.
Request example
POST /v1/candidates
{
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"dob": "1990-01-15",
"zipcode": "90210"
}
Response example
{
"id": "e44aa283528e6fde7d542194",
"object": "candidate",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com",
"created_at": "2024-01-10T12:00:00Z"
}
Retrieve Candidate
- Method: GET
- URL:
https://api.checkr.com/v1/candidates/{id} - Watch out for: SSN is masked in all GET responses.
Request example
GET /v1/candidates/e44aa283528e6fde7d542194
Response example
{
"id": "e44aa283528e6fde7d542194",
"object": "candidate",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane.doe@example.com"
}
Update Candidate
- Method: POST
- URL:
https://api.checkr.com/v1/candidates/{id} - Watch out for: Checkr uses POST (not PATCH) for updates to existing candidates.
Request example
POST /v1/candidates/e44aa283528e6fde7d542194
{
"phone": "5551234567"
}
Response example
{
"id": "e44aa283528e6fde7d542194",
"phone": "5551234567",
"updated_at": "2024-01-11T08:00:00Z"
}
List Candidates
- Method: GET
- URL:
https://api.checkr.com/v1/candidates - Watch out for: Results are paginated; use next_href to iterate pages.
Request example
GET /v1/candidates?page=1&per_page=25
Response example
{
"data": [{"id": "e44aa...", "first_name": "Jane"}],
"object": "list",
"next_href": "https://api.checkr.com/v1/candidates?page=2"
}
Create Invitation (send candidate invite)
- Method: POST
- URL:
https://api.checkr.com/v1/invitations - Watch out for: Invitations expire; check expiration settings in the dashboard.
Request example
POST /v1/invitations
{
"package": "driver_pro",
"candidate_id": "e44aa283528e6fde7d542194",
"work_locations": [{"country": "US"}]
}
Response example
{
"id": "inv_abc123",
"status": "pending",
"invitation_url": "https://apply.checkr.com/..."
}
Create Report (background check)
- Method: POST
- URL:
https://api.checkr.com/v1/reports - Watch out for: Candidate must have sufficient PII (SSN, DOB) before a report can be created without an invitation flow.
Request example
POST /v1/reports
{
"package": "driver_pro",
"candidate_id": "e44aa283528e6fde7d542194"
}
Response example
{
"id": "report_xyz789",
"status": "pending",
"candidate_id": "e44aa283528e6fde7d542194"
}
Retrieve Report
- Method: GET
- URL:
https://api.checkr.com/v1/reports/{id} - Watch out for: Poll status or use webhooks; do not rely solely on synchronous response for final status.
Request example
GET /v1/reports/report_xyz789
Response example
{
"id": "report_xyz789",
"status": "clear",
"result": "clear",
"candidate_id": "e44aa283528e6fde7d542194"
}
List Geos (work locations/nodes)
- Method: GET
- URL:
https://api.checkr.com/v1/geos - Watch out for: Geos are account-specific; must be configured in the dashboard before use in reports.
Request example
GET /v1/geos
Response example
{
"data": [{"id": "geo_001", "name": "California", "state": "CA"}]
}
Rate limits, pagination, and events
- Rate limits: Checkr enforces rate limits per API key. Exact published limits are not publicly documented in detail.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: HTTP 429 is returned when rate limits are exceeded. Checkr recommends exponential backoff. Specific numeric limits are not published in official docs.
- Pagination method: cursor
- Default page size: 25
- Max page size: 100
- Pagination pointer: page
| Plan | Limit | Concurrent |
|---|---|---|
| Standard | Not publicly specified | 0 |
| Enterprise | Custom / higher limits available | 0 |
- Webhooks available: Yes
- Webhook notes: Checkr supports webhooks to notify your application of background check status changes and other events. Webhooks are configured in the Checkr Dashboard under Developer Settings.
- Alternative event strategy: Polling the GET /v1/reports/{id} endpoint is an alternative but not recommended for production.
- Webhook events: report.created, report.completed, report.updated, candidate.created, candidate.updated, invitation.created, invitation.completed, invitation.expired, adverse_action.created, adverse_action.finalized
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://api.checkr.com/scim/v2
Supported operations: Create User, Read User, Update User, Deactivate User, List Users, Create Group, Read Group, Update Group, Delete Group
Limitations:
- Requires Enterprise plan
- SSO must be configured as a prerequisite
- Supported IdPs include Okta, Microsoft Entra ID (Azure AD), and Google Workspace
- SCIM manages dashboard user accounts (admins/team members), not background check candidates
- OneLogin is not listed as a supported IdP in official docs
Common scenarios
Three integration patterns cover the majority of Checkr API use cases. For candidate onboarding: POST /v1/candidates to create the record, then POST /v1/invitations to send the candidate a consent-and-PII collection link; the report is created after the candidate completes the invitation.
For direct report creation without an invitation flow, the candidate must already have SSN and DOB on file - missing PII causes report creation to fail at the request level.
For dashboard user provisioning (Enterprise only): configure your IdP to POST to the SCIM /Users endpoint; deprovisioning sends a PATCH with active=false. Webhook-driven status handling via report.
completed is the correct production pattern; polling GET /v1/reports/{id} is documented but not recommended at scale.
Onboard a new candidate and initiate a background check
- POST /v1/candidates with first_name, last_name, email to create the candidate record.
- Store the returned candidate id.
- POST /v1/invitations with the candidate_id and desired package to send the candidate an invitation link.
- Candidate completes the invitation form providing consent and PII.
- Receive report.completed webhook event when the background check finishes.
- GET /v1/reports/{report_id} to retrieve the final result.
Watch out for: If you skip the invitation flow and POST directly to /v1/reports, the candidate must already have SSN and DOB on file; otherwise the report creation will fail.
Provision a new dashboard admin via SCIM (Enterprise)
- Ensure SSO is configured in Checkr Dashboard (Okta, Entra, or Google Workspace).
- Configure SCIM provisioning in your IdP pointing to https://api.checkr.com/scim/v2.
- Assign the user in your IdP; the IdP sends a SCIM POST /Users request to Checkr.
- Checkr creates the dashboard user account and sends an activation email.
- To deprovision, unassign the user in the IdP; the IdP sends a SCIM PATCH /Users/{id} with active=false.
Watch out for: SCIM only manages dashboard team members, not candidates. Enterprise plan and SSO are both required.
Monitor report status changes via webhooks
- In Checkr Dashboard > Developer Settings, add a webhook endpoint URL.
- Store the webhook signing secret provided by Checkr.
- Verify incoming webhook payloads by checking the X-Checkr-Signature header against an HMAC-SHA256 of the payload using your signing secret.
- Handle report.completed events to trigger downstream workflows (e.g., update applicant status in your ATS).
- Return HTTP 200 promptly; Checkr retries on non-2xx responses.
Watch out for: Failing to verify the webhook signature exposes your endpoint to spoofed events. Always validate before processing.
Why building this yourself is a trap
Several non-obvious behaviors create integration risk. Checkr uses POST - not PATCH - for candidate updates, which diverges from REST convention and can cause confusion in generic HTTP client wrappers. Duplicate candidate records are not prevented by the API: submitting the same email twice creates two distinct candidate objects with no deduplication.
Rate limit thresholds are not publicly documented; the API returns HTTP 429 on breach, and exponential backoff is the only documented mitigation. SSN and other sensitive PII fields are masked in all GET responses, so any workflow that needs to verify PII must rely on the invitation flow rather than read-back.
Finally, background check packages must be pre-configured in the dashboard before they can be referenced in API calls - referencing an unconfigured package slug will fail at report creation time.
Automate Checkr workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.