Errors
CoreVerify uses standard HTTP status codes to indicate success or failure. When a request fails, the response body contains an error object with a machine-readable code and a human-readable message.
Error Response Format
{
"error": {
"code": "candidate_not_found",
"message": "No candidate found with that ID",
"status": 404
}
}| Field | Type | Description |
|---|---|---|
| code | string | Machine-readable error code for programmatic handling |
| message | string | Human-readable description of the error |
| status | integer | HTTP status code (mirrors the response status) |
| details | object[] | Present on validation errors — array of field-level errors |
4xx Client Errors
These errors indicate a problem with your request. Fix the issue before retrying.
400Bad Request
| Code | Description |
|---|---|
| bad_request | The request is malformed or missing required fields |
| validation_error | One or more fields failed validation. See details for field-level errors |
400 validation_error
{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"status": 400,
"details": [
{
"field": "email",
"message": "Must be a valid email address"
},
{
"field": "phone",
"message": "Must be in E.164 format (e.g. +15551234567)"
}
]
}
}401Unauthorized
| Code | Description |
|---|---|
| unauthorized | No API key was provided, or the key is invalid / revoked |
403Forbidden
| Code | Description |
|---|---|
| forbidden | Your API key does not have permission to perform this action (e.g. using a publishable key for a write operation) |
404Not Found
| Code | Description |
|---|---|
| not_found | Generic not found — the requested resource does not exist |
| candidate_not_found | No candidate exists with the given ID |
| report_not_found | No report exists with the given ID |
| package_not_found | No package exists with the given ID, or it is inactive |
409Conflict
| Code | Description |
|---|---|
| conflict | The request conflicts with the current state — for example, ordering a report for a candidate that already has an active report |
422Unprocessable Entity
| Code | Description |
|---|---|
| unprocessable_entity | The request is syntactically valid but cannot be processed due to semantic errors — for example, attempting to adjudicate a report that has not yet completed |
429Too Many Requests
| Code | Description |
|---|---|
| rate_limit_exceeded | You have exceeded the API rate limit. Check the Retry-After response header for the number of seconds to wait before retrying |
429 rate_limit_exceeded
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710590430
{
"error": {
"code": "rate_limit_exceeded",
"message": "API rate limit exceeded. Retry after 30 seconds.",
"status": 429
}
}5xx Server Errors
These errors indicate a problem on CoreVerify's side. They are rare, but when they occur you should retry the request with exponential backoff.
500Internal Server Error
| Code | Description |
|---|---|
| internal_error | An unexpected error occurred on CoreVerify's servers. If this persists, contact support with the request ID from the response headers |
Handling Errors
We recommend checking the error.code field rather than the HTTP status code for fine-grained handling in your application.
TypeScript
const res = await fetch('https://api.coreverify.com/v1/candidates/cand_abc', {
headers: { Authorization: `Bearer ${apiKey}` }
})
if (!res.ok) {
const { error } = await res.json()
switch (error.code) {
case 'candidate_not_found':
// Handle missing candidate
break
case 'unauthorized':
// Refresh or prompt for new API key
break
case 'rate_limit_exceeded':
// Retry after delay
const retryAfter = res.headers.get('Retry-After')
await delay(parseInt(retryAfter ?? '5', 10) * 1000)
break
default:
throw new Error(`API error: ${error.message}`)
}
}
const { data } = await res.json()