Skip to main content
The Enrow API signals problems with HTTP status codes and a JSON error body. This guide explains the error response formats, the most common errors and how to fix them, and how to build reliable retry logic. For the complete list of codes, see Status codes.

What does an error response look like?

Most Enrow API errors return a simple JSON object with a single message field:
{
  "message": "Human-readable error description"
}
The one exception is an insufficient-credit (402) error on single endpoints (email/phone find single, verify single), which returns a reason field alongside success:
{
  "reason": "Insufficient credits",
  "success": false
}
Error responses never include error, status, or retry_after fields. Read the HTTP status code to branch your logic, and read message (or reason) for the human-readable description.

What are the most common errors and how do I fix them?

The errors below cover the vast majority of failed requests. Each one comes with the response body the API returns and the fix.

Why am I getting a 400 Bad Request?

A 400 means the request payload is malformed or missing a required parameter:
{
  "message": "both company_domain and company_name are absent, input payload needs at least one of them"
}
Fix: Check that you’re providing all required parameters for the endpoint. For example, Find Single Email requires fullname plus either company_domain or company_name.

Why am I getting a 401 Unauthorized?

A 401 means the API key is missing or invalid:
{
  "message": "This apikey is not valid"
}
Fix: Verify the API key is correct and sent in the x-api-key header (not Authorization). See Authentication for how to pass the key on every request.

Why am I getting a 402 Insufficient Credits?

A 402 means the account doesn’t have enough credits to run the request:
{
  "reason": "Insufficient credits",
  "success": false
}
On bulk endpoints, the same 402 is returned with the standard { "message": "..." } shape instead. Fix: Check the credit balance on the Dashboard or via GET /account/info. Top up credits or upgrade the plan at enrow.io/pricing. See Credits & billing for how credits are consumed per endpoint.

Why am I getting a 429 Rate Limit Exceeded?

A 429 means too many requests were sent in a short window:
{
  "message": "Too Many Requests"
}
Fix: Wait and retry with exponential backoff. See Rate limits for the limits per plan.

Why am I getting a 500 Internal Server Error?

A 500 means something failed on Enrow’s side:
{
  "message": "An unexpected error occurred"
}
Fix: Retry the request with backoff. If the issue persists, contact api@enrow.io.

How do I handle errors in code?

Check the HTTP status before parsing the success body, then raise an error that carries the status code so your retry logic can branch on it. The message field holds the description for most errors, and reason holds it for single-endpoint 402 responses.
async function findEmail(contact) {
  const response = await fetch('https://api.enrow.io/email/find/single', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.ENROW_API_KEY
    },
    body: JSON.stringify(contact)
  });

  if (!response.ok) {
    const body = await response.json();
    const error = new Error(`Enrow API error ${response.status}: ${body.message || body.reason}`);
    error.status = response.status;
    throw error;
  }

  return await response.json();
}

How do I retry failed requests?

Retry only the errors that are worth retrying — 429 and 5xx — and back off exponentially between attempts. Client errors in the 4xx range (except 429) signal a problem with the request itself, so retrying them won’t help.
async function requestWithRetry(fn, maxRetries = 3, baseDelay = 1000) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const isLastAttempt = attempt === maxRetries - 1;

      // Don't retry client errors (except rate limits)
      if (error.status >= 400 && error.status < 500 && error.status !== 429) {
        throw error;
      }

      if (isLastAttempt) throw error;

      const delay = baseDelay * Math.pow(2, attempt);

      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Best practices

  • Don’t retry 4xx errors (except 429) — fix the request instead
  • Retry 429 errors — back off with exponential delays before retrying
  • Retry 5xx errors — with exponential backoff
  • Use webhooks instead of polling to avoid hitting rate limits unnecessarily — see How webhooks work
  • Log errors with context — include the endpoint, parameters, and timestamp for debugging

FAQ

On single endpoints (email/phone find single, verify single), a 402 returns { "reason": "Insufficient credits", "success": false }. On bulk endpoints, the same 402 returns the standard { "message": "..." } shape. Reading both message and reason (as the code examples do) handles either case.
Retry 429 (rate limit) and 5xx (server) errors with exponential backoff. Do not retry other 4xx errors such as 400, 401, or 402 — they indicate a problem with the request, the API key, or the credit balance that retrying alone won’t fix.
No. Error responses never include retry_after, error, or status fields. Use your own exponential backoff between retries. See Rate limits for the limits that apply to your plan.
For most errors, the description is in the message field. For an insufficient-credit 402 on a single endpoint, it’s in the reason field instead. Always branch your logic on the HTTP status code rather than parsing the message text.

Next steps

Status codes

The complete list of HTTP status codes and their meanings.

Rate limits

Understand the request limits per plan to avoid 429 errors.

Authentication

How to pass your API key in the x-api-key header.

Credits & billing

See how credits are consumed for each endpoint.