Every error response follows the same structure and includes a clear error code you can match on programmatically.
Response format
Every error follows the same JSON structure. Match on the code field to handle specific cases in your code:
{
"success": false,
"data": null,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits: 0 available, 1 required"
},
"metadata": {
"requestId": "00bc3fa0-348f-4955-a1c1-3c7c91234568",
"executionTimeMs": 3
}
}
Note
Always include metadata.requestId when contacting support. It lets us trace your request instantly.
Error reference
| Status | What to do |
|---|---|
422 |
Check your request body: a required field is missing or malformed (INVALID_LINKEDIN_URL is also returned for an invalid URL). For async endpoints, make sure a webhook URL is configured. On the search endpoints, see Search filter validation for the exact reason. |
401 |
Check your API key: it may be missing, malformed, invalid, or expired. See Authentication. |
402 |
No credits left. Paid lookups (INSUFFICIENT_CREDITS) and the free /check endpoints (NO_CREDITS) are both blocked until you top up. Purchase more or upgrade your plan. |
403 |
Your workspace may be disabled (WORKSPACE_DISABLED), your key may lack a required permission, or the endpoint may require a paid plan. Upgrade to unlock live enrichment, email discovery, and more. |
404 |
No result found for your query. Some endpoints still charge credits; see Not found pricing. |
429 |
Rate limit reached. Wait and retry with backoff (see below). |
451 |
This person has been removed per GDPR/CCPA. Enrichment is permanently blocked. |
503 |
Our service is temporarily unavailable. Retry with backoff (see below). |
504 |
The lookup took too long and timed out. Retry with backoff (see below). |
Search filter validation
The search endpoints validate every filter before running the query. A rejected request returns 422, costs 0 credits, and never reaches the database. This is deliberate: a filter we cannot honour would otherwise return an empty page that looks like a legitimate “no results”, and bill you for it.
error.details.errors always lists every problem found, so one round trip is enough to fix a whole payload.
error.code |
Meaning |
|---|---|
UNKNOWN_FIELD |
The field does not exist. Unknown fields are rejected rather than ignored, because an ignored filter returns unfiltered results. details.suggestion gives the closest accepted field, details.acceptedFields lists them all. |
INVALID_FILTER_VALUE |
The value is outside a closed list. This covers industry and country values plus the People Search currentFunction, currentSubFunction and currentSeniority taxonomies. details.suggestions proposes up to three valid values. |
EMPTY_FILTER_VALUE |
A blank string, empty array or empty object was sent. Remove the field instead. |
FILTER_VALUES_LIMIT_EXCEEDED |
A filter carries more than 20 values. Split it into searches of at most 20 values and merge the results. |
INVALID_RANGE |
A min/max pair is negative, fractional, or inverted (min greater than max). |
INCOMPLETE_RANGE_FILTER |
followersCount used as the only filter requires both bounds. |
INVALID_PAGINATION |
perPage, or page on Company Search, is not a whole number. |
PAGINATION_LIMIT_EXCEEDED |
perPage is above 100, or page is above 50 on Company Search. details carries field and max. |
INVALID_ID_FORMAT |
currentCompanyId is not a com_ identifier returned by our API. |
INVALID_DATE_FORMAT |
maxDataAgeDate is not an ISO 8601 date-time. |
CONTRADICTORY_FILTERS |
The same value appears in an included and excluded filter, which can never match. |
NO_FILTER_PROVIDED |
The body carries pagination only: cursor / perPage for People Search or page / perPage for Company Search. |
INVALID_SEARCH_FILTERS |
Several of the above at once. Read details.errors. |
{
"success": false,
"data": null,
"error": {
"code": "INVALID_FILTER_VALUE",
"message": "\"Technology\" is not an accepted value for \"industry\". Did you mean \"Technology, Information and Internet\", \"Technology, Information and Media\"? This filter is matched exactly, so an unlisted value can never return a result.",
"details": {
"field": "industry",
"value": "Technology",
"reason": "not_in_accepted_values",
"suggestions": ["Technology, Information and Internet", "Technology, Information and Media"],
"documentation": "https://docs.reversecontact.com/guides/industries"
}
}
}
Values are compared tolerantly before being rejected: case, surrounding spaces, accents and & versus and are normalised for you. Only a genuinely unknown value is refused.
When to retry
These statuses are safe to retry with exponential backoff:
429you’ve hit a rate limit. Wait for the reset window and retry.503temporary service issue. Retry after a short delay.504the lookup timed out before completing. Retry after a short delay.
All other errors require a change to your request or configuration before retrying.
Wait a little longer between each retry to give the server time to recover:
const delay = Math.min(1000 * 2 ** attempt, 15000)
const jitter = Math.floor(Math.random() * 250)
await new Promise((r) => setTimeout(r, delay + jitter))
delay = min(1 * 2 ** attempt, 15)
jitter = random.uniform(0, 0.25)
time.sleep(delay + jitter)
Credits and errors
All error responses (401, 402, 403, 422, 429, 451, 503, 504) cost 0 credits.
The 404 status is the only exception: some endpoints charge credits when the lookup was performed but no result was found. See Not found pricing for the full breakdown.