Error Handling
How Gonos reports errors and how to handle them in your integration.
Error response format
All error responses follow a consistent JSON structure:
{
"detail": "Human-readable error message",
"error_code": "MACHINE_READABLE_CODE",
"correlation_id": "abc123-def456",
"errors": [
{
"field": "email",
"message": "Not a valid email address"
}
]
}| Field | Description |
|---|---|
detail | Human-readable description of the error |
error_code | Machine-readable error code for programmatic handling |
correlation_id | Unique ID for the request — include this when contacting support |
errors | Array of field-level validation errors (only on 422 responses) |
HTTP status codes
| Code | Meaning | When |
|---|---|---|
400 | Bad Request | Malformed JSON, missing required fields |
401 | Unauthorized | Missing or invalid API key / JWT token |
403 | Forbidden | Valid credentials but insufficient scope or permissions |
404 | Not Found | Resource does not exist or does not belong to your organization |
409 | Conflict | Duplicate resource (e.g., idempotency key reuse) |
422 | Validation Error | Request understood but contains invalid data |
429 | Too Many Requests | Rate limit exceeded — check Retry-After header |
500 | Internal Error | Unexpected server error — safe to retry |
Common error codes
| Error Code | Description |
|---|---|
CONSENT_REQUIRED | Background check requires consumer consent first |
CONSENT_EXPIRED | Consent has expired and must be recaptured |
CANDIDATE_NOT_FOUND | The specified candidate ID does not exist |
CHECK_NOT_FOUND | The specified check ID does not exist |
INVALID_PACKAGE | The check package name is not recognized |
INVALID_PURPOSE | The permissible purpose is not a valid FCRA purpose |
QUOTA_EXCEEDED | Monthly check quota has been reached |
DUPLICATE_CHECK | A check with this idempotency key already exists |
FCRA_MANDATORY_TYPE | Cannot unsubscribe from FCRA-mandatory notification types |
CERTIFICATION_REQUIRED | Purpose certification must be acknowledged |
Retry strategies
Safe to retry
429responses — wait for theRetry-Afterheader duration500responses — use exponential backoff (1s, 2s, 4s, 8s, 16s)- Network timeouts or connection errors
Do not retry
400,401,403,404— fix the request first409— the resource already exists, fetch it instead422— fix the validation errors in your payload
Example: exponential backoff
import time
import httpx
def request_with_retry(method, url, **kwargs):
max_retries = 5
for attempt in range(max_retries):
response = httpx.request(method, url, **kwargs)
if response.status_code == 429:
wait = int(response.headers.get("Retry-After", 60))
time.sleep(wait)
continue
if response.status_code >= 500:
time.sleep(2 ** attempt)
continue
return response
raise Exception("Max retries exceeded")Getting help
When contacting support about an error, always include the correlation_id from the error response. This allows us to trace the exact request through our systems.