Error Codes
All errors return a consistent JSON format:
{
"error": "Human-readable error message",
"code": "ERROR_CODE",
"details": []
}
HTTP Status Codes
| Status | Meaning | When It Occurs |
|---|---|---|
200 | OK | Request succeeded |
202 | Accepted | Async job started (enrichment) |
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Authentication failed |
403 | Forbidden | Access denied |
404 | Not Found | Resource doesn't exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Error | Server-side error |
503 | Service Unavailable | Feature temporarily disabled |
Error Code Reference
Authentication & Authorization
| Code | Status | Description | Solution |
|---|---|---|---|
AUTHENTICATION_FAILED | 401 | API key missing, invalid, or revoked | Check Authorization: Bearer YOUR_KEY header; verify key is active in Dashboard > API Keys |
NO_TEAM | 403 | User not associated with a team | Contact support |
NO_API_KEY | 400 | No active API key found | Create a key in Dashboard > API Keys |
Validation
| Code | Status | Description | Solution |
|---|---|---|---|
VALIDATION_ERROR | 400 | Request body failed validation | Check the details array for specific field errors |
INVALID_REQUEST | 400 | Request body is not valid JSON | Validate JSON syntax; ensure Content-Type: application/json |
Rate Limiting
| Code | Status | Description | Solution |
|---|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Plan rate limit exceeded | Wait for Retry-After header value, then retry. See Rate Limits |
Rate limit responses include extra fields:
{
"code": "RATE_LIMIT_EXCEEDED",
"limit": 100,
"remaining": 0,
"reset": 1705320000,
"retryAfter": 3600
}
Resources
| Code | Status | Description | Solution |
|---|---|---|---|
JOB_NOT_FOUND | 404 | Job doesn't exist or belongs to another team | Verify the jobId from the original /enrich response |
NOT_FOUND | 404 | Resource doesn't exist | Check the resource ID |
Bulk Enrichment
| Code | Status | Description | Solution |
|---|---|---|---|
NO_VALID_DOMAINS | 400 | All provided domains failed validation | Use valid formats: stripe.com, www.stripe.com, https://stripe.com |
BULK_DISABLED | 503 | Bulk imports temporarily disabled | Try again later or use single enrichment |
QUEUE_FAILED | 500 | Failed to queue domains | Retry the request; contact support with batchId if persistent |
Server
| Code | Status | Description | Solution |
|---|---|---|---|
INTERNAL_ERROR | 500 | Unexpected server error | Retry with backoff; check status.veraenrich.com |
INVALID_STATUS | 500 | Job in unexpected state | Retry fetching job status; contact support with job ID |
Error Handling Best Practices
- 4xx errors — Don't retry. Fix the request (check auth, validation, resource IDs).
- 429 errors — Wait for the
Retry-Afterheader value, then retry. See Rate Limits. - 5xx errors — Retry with exponential backoff (1s, 2s, 4s...). Check status.veraenrich.com if persistent.
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (true) {
case response.status === 429:
// Rate limited — wait and retry
const retryAfter = response.headers.get('Retry-After') || '60';
await new Promise(r => setTimeout(r, parseInt(retryAfter) * 1000));
break;
case response.status >= 500:
// Server error — retry with exponential backoff
break;
default:
// Client error (4xx) — don't retry, fix the request
throw new Error(`${error.code}: ${error.error}`);
}
}
For complete retry patterns with backoff, see Rate Limits.