Skip to content
Datasource Background Check Partner API

Error catalog

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

{
  "type": "https://partners.cbgc.io/docs/errors.md#client_not_found",
  "title": "Client not found",
  "status": 404,
  "detail": "No client 'org-1042' 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 { "level": ["level is required."] }. Messages never repeat the values you sent.

Two documented responses are not problem details:

  • 409 on POST /clients/{clientRef}/checks with code duplicate_check: the body is { code, message, currentStatus, instructions, order }, with the existing check in order.
  • 502 on POST /clients/{clientRef}/checks 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_return_url 400 No Register the URL with PUT /settings, then create the session again.
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 test, pk_live_ on production).
client_not_found 404 No Check the clientGuid or externalClientId; only your own clients resolve.
check_not_found 404 No Check the orderId, externalIdentifier or id, and the client.
batch_not_found 404 No Check the batchId; only your own batches resolve.
session_not_found 404 No Check the sessionId; only your own sessions resolve.
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 client: GET /clients?externalClientId=....
client_already_connected 409 No The church is already connected; use its client instead of a new session.
external_identifier_in_use 409 No Use a different externalIdentifier (it is unique across all your clients).
batch_in_progress 409 Yes, later Wait until the client's running batch is completed, then send again.
check_not_awaiting_applicant 409 No Only a check waiting for the applicant can be re-sent.
reminder_too_soon 409 Yes, later Wait an hour after the last reminder.
payload_too_large 413 No Send a smaller body (for example fewer applicants per batch).
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, a value is too long, a URL isn't https://, level is missing, and so on. errors lists each problem by field name (nested fields as orderedBy.email, list entries as connectReturnUrls[0]). Nothing was created or changed. Retry: only after fixing the request.

invalid_cursor

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

invalid_return_url

400. On POST /connect/sessions, returnUrl doesn't exactly match one of your registered connectReturnUrls (matching is exact: scheme, host, path and query). Nothing was created. Retry: after registering it with PUT /settings.

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 (for example limit=abc or an updated_since that isn't ISO 8601). 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.

client_not_found

404. No client with that clientGuid or externalClientId exists under your account. Clients of other partners always look like this. Retry: no.

check_not_found

404. No check with that orderId, externalIdentifier or numeric id exists for the client (or, on routes without a client, under your account). Retry: no.

batch_not_found

404. No batch with that batchId exists under your account. Retry: no.

session_not_found

404. No connect session with that sessionId exists under your account. Sessions are deleted 7 days after they end. 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 test environment). 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: the applicant (same externalIdentifier, or same email at this client) already has a check that is in progress (QUEUED, PENDING, CREATED) or completed and not yet expired (CLEAR, REVIEW). Nothing was ordered or billed. The body is not problem details:

{
  "code": "duplicate_check",
  "message": "A background check is currently in progress with status 'CREATED'.",
  "currentStatus": "CREATED",
  "instructions": "To force a re-order, submit the request with 'forceReorder': true.",
  "order": { "id": "chk_9c2e4f6a1b3d4e5f8a7b6c5d", "externalIdentifier": "vol-8841", "clientId": "cl_5b0e6f2a8c1d4e7b9a3f2d6c", "status": "CREATED", "stage": "awaiting_applicant" }
}

(order is the full check; shortened here.) If you were retrying after a timeout, this means 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 clients already has this externalClientId. Nothing was created. Retry: no; use the existing client.

client_already_connected

409. On POST /connect/sessions: a client with this externalClientId is already active under your account. Retry: no; look it up with GET /clients?externalClientId=....

external_identifier_in_use

409. The externalIdentifier is taken. On POST /clients/{clientRef}/checks: it belongs to a check of another of your clients (an externalIdentifier is unique across all your clients); nothing was ordered. On PATCH /clients/{clientRef}/checks/{orderId}: the check already has one (it can be set once), or another check uses the value; nothing changed. In a batch the same situation is an invalid item, not this error. Retry: no; use a different value.

batch_in_progress

409. On POST /clients/{clientRef}/checks/batch: this client already has a batch that is still running (a batch counts as running for at most 24 hours). Nothing was ordered. Retry: yes, once GET /batches/{batchId} shows the other batch completed. Sending the same batchReference as a running batch is not this error: it returns that batch.

check_not_awaiting_applicant

409. On POST /clients/{clientRef}/checks/{checkRef}/remind: the check isn't waiting for the applicant (status CREATED, stage awaiting_applicant). The applicant already finished, or the check is closed. Nothing was sent. Retry: no.

reminder_too_soon

409. On POST /clients/{clientRef}/checks/{checkRef}/remind: the applicant was re-sent the invitation less than an hour ago (detail says when). Nothing was sent. Retry: yes, an hour after the last reminder.

payload_too_large

413. The request body is larger than the server accepts. Retry: no; send less (a batch holds at most 500 applicants).

unsupported_media_type

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

level_not_available

422. The client has no product for that level. This is a configuration problem on our side. Nothing was ordered. Retry: no; pick a level from GET /clients/{clientRef}/products, or contact support.

rate_limited

429. Either too many requests with an invalid API key came from your IP address (20 a minute; valid keys are never throttled this way), or more than 30 connect sessions were created in a minute. Retry-After gives the seconds to wait (an integer, 60 for both). Retry: yes, after waiting.

internal_error

500. Something failed on our side. The body is a problem details object with code: internal_error and a traceId to quote to support; it 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; contact support with the time of the request if it keeps happening.

upstream_unavailable

502. The screening provider didn't accept the request. As problem details, nothing was created or recorded and a retry is safe: this is the case for clients, products and batches, and for an order when the church's account couldn't be prepared for ordering.

For POST /clients/{clientRef}/checks 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 (you'll get the check or 409 duplicate_check), or just wait: a PENDING check is looked up with the provider automatically and resolved within about an hour, and you get check.updated either way (its real status if the provider has it, or ERROR if it never arrived, after which ordering again is allowed).

If the body is a check with status ERROR, the screening provider refused that order outright (for example a product that needs fields this API doesn't collect). Nothing was created or billed, and you can order again once the cause is fixed; contact support if it persists.

request_failed

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