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:
409onPOST /clients/{clientRef}/checkswithcodeduplicate_check: the body is{ code, message, currentStatus, instructions, order }, with the existing check inorder.502onPOST /clients/{clientRef}/checkswhen the body is a check (statusPENDINGorERROR, nocode). 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.