Skip to content
Datasource Wholesale Background Check API

Error catalog

Every error response is RFC 9457 problem details (Content-Type: application/problem+json) with a stable code. Its type is https://api.datasourcecorp.app/docs/errors.md#<code>, a link to the entry below. Branch on code: titles and details are for people and may change.

{
  "type": "https://api.datasourcecorp.app/docs/errors.md#client_not_found",
  "title": "Client not found",
  "status": 404,
  "detail": "No client 'acct-7731' exists under your account.",
  "code": "client_not_found"
}

Validation errors (validation_failed, invalid_cursor) also carry errors: an object from field name to a list of messages, for example { "applicant.ssn": ["applicant.ssn must be a valid 9-digit Social Security number."] }. Messages never repeat the values you sent.

Two documented responses are not problem details:

  • 409 on POST /clients/{clientRef}/checks/direct with code duplicate_check: the body is { code, message, currentStatus, instructions, order }, with the existing check in order.
  • 502 on POST /clients/{clientRef}/checks/direct when the body is a check (status PENDING or ERROR, no code). See upstream_unavailable.

Read the HTTP status first, then code when the body has one.

All codes

code HTTP Retry the same request? What to do
validation_failed 400 No Fix each field named in errors, then send again.
invalid_cursor 400 No Start again from the first page (omit cursor).
invalid_json 400 No Send a valid JSON body with Content-Type: application/json, and values of the right type.
invalid_api_key 401 No Use a valid key for this environment (pk_test_ on the sandbox, pk_live_ on production).
not_available_for_account_type 403 No The operation isn't part of the wholesale API. Use the operations in this reference.
client_not_found 404 No Use account, or a sub-account's clientId or externalClientId.
check_not_found 404 No Check the id or externalIdentifier, and the account it was ordered on.
not_found 404 No The route doesn't exist. Check the method and path.
method_not_allowed 405 No Use the method the reference lists for this path.
duplicate_check 409 No Use the existing check in order. Only send forceReorder: true if you want a new, billed check.
external_client_id_in_use 409 No Use the existing sub-account: GET /clients?externalClientId=....
external_identifier_in_use 409 No Use a different externalIdentifier (it is unique across your account and sub-accounts).
payload_too_large 413 No Send a smaller body.
unsupported_media_type 415 No Send Content-Type: application/json.
level_not_available 422 No Pick a level from GET /clients/{clientRef}/products, or contact support.
rate_limited 429 Yes, after Retry-After Wait the number of seconds in Retry-After, then send again.
internal_error 500 Yes, with the same externalIdentifier Retry with backoff; contact support if it persists.
upstream_unavailable 502 Usually; see the entry Retry with backoff. For orders, read the entry first.
request_failed other Depends Any other framework error. Read status and detail.

validation_failed

400. The request is invalid: a required field is missing or malformed (an SSN that can't be issued, a date of birth that isn't YYYY-MM-DD, an unknown state), a value is too long, or the certification is incomplete. errors lists each problem by field path (applicant.address.postalCode, certification.authorizationObtained). Nothing was created or billed. Retry: only after fixing the request.

invalid_cursor

400. On GET /clients/{clientRef}/checks, cursor is not a nextCursor we issued. Retry: no; start again from the first page.

invalid_json

400. The body isn't valid JSON, is missing, or a value has the wrong type (for example "level": "two"), or a query value can't be read. Nothing was created. Retry: after fixing the request.

invalid_api_key

401. The API key is missing, invalid or revoked, or it belongs to the other environment. Retry: only with a valid key. Repeated invalid keys from one IP address lead to rate_limited.

not_available_for_account_type

403. The operation exists on this server but isn't part of the wholesale API (for example ordering by invitation, or the hosted connect page). Nothing was done. Retry: no.

client_not_found

404. {clientRef} isn't account or one of your sub-accounts. Other customers' accounts always look like this. Retry: no.

check_not_found

404. No check with that id or externalIdentifier exists on that account. Retry: no.

not_found

404. No such route. Check the method, the path, and that you're calling the right environment (some routes exist only in the sandbox). Retry: no.

method_not_allowed

405. The path exists but not with this HTTP method. Retry: no.

duplicate_check

409. On POST /clients/{clientRef}/checks/direct: the applicant (same externalIdentifier, or same SSN on the same account) already has a check that is in progress (PENDING, CREATED) or completed and not yet expired (CLEAR, REVIEW). Nothing was ordered or billed. The body is not problem details: it is { code, message, currentStatus, instructions, order } with the existing check in order. If you were retrying after a timeout, your first attempt worked: use order. Retry: no. forceReorder: true orders anyway and is billed as a new check.

external_client_id_in_use

409. On POST /clients: another of your sub-accounts already has this externalClientId. Nothing was created. Retry: no; use the existing sub-account.

external_identifier_in_use

409. The externalIdentifier is taken. On an order: it belongs to a check on another of your accounts; nothing was ordered. On PATCH /clients/{clientRef}/checks/{checkRef}: the check already has one (it can be set once), or another check uses the value; nothing changed. Retry: no; use a different value.

payload_too_large

413. The request body is larger than the server accepts. Retry: no.

unsupported_media_type

415. The body isn't sent as Content-Type: application/json. Retry: no; set the header.

level_not_available

422. The account has no product for that level. Nothing was ordered. Retry: no; pick a level from GET /clients/{clientRef}/products, or contact support.

rate_limited

429. Too many requests with an invalid API key came from your IP address (20 a minute; valid keys are never throttled this way). Retry-After gives the seconds to wait. Retry: yes, after waiting.

internal_error

500. Something failed on our side. The body has a traceId to quote to support and never contains error details. For an order, the check may or may not exist: retry only with the same externalIdentifier, and expect either a normal result or 409 duplicate_check. Retry: yes, with backoff.

upstream_unavailable

502. The screening provider didn't accept the request. As problem details, nothing was created or recorded and a retry is safe.

For an order the body can instead be the check itself (status PENDING, no code): the order was sent but its answer was lost, so it may or may not exist upstream. Don't retry with forceReorder. Retry only with the same externalIdentifier, or just wait: a PENDING check is looked up automatically and resolved within about an hour, and you get check.updated either way.

If the body is a check with status ERROR, the screening provider refused that order outright (errorCode and errorMessage say why). Nothing was created or billed; order again once the cause is fixed.

request_failed

Any other status the framework produces (rare). Read status and detail. Retry: depends on the status.