> Reverse Contact API documentation. This is the Markdown copy of https://docs.reversecontact.com/sdk/javascript/errors-and-retries
> Every page is listed at https://docs.reversecontact.com/llms.txt, every endpoint with its credit cost and status at https://docs.reversecontact.com/catalog.json

# Errors and retries

> Handle typed errors and automatic retries in the Reverse Contact TypeScript SDK, and reuse idempotency keys for Find Email, Verify Email and Find Phone.

- Last verified: 2026-11-04

Catch SDK errors by class and preserve the request id when reporting an API failure.

## Error classes and retry policy

Every SDK error extends `ReverseContactError`. Errors returned by the API extend `APIError` and include `status`, `code`, `message`, `details`, `requestId`, `headers` and `body`.

| HTTP status | Error class |
| ----------- | ----------- |
| `400` | `BadRequestError` |
| `401` | `AuthenticationError` |
| `402` | `InsufficientCreditsError` |
| `403` | `PermissionDeniedError` |
| `404` | `NotFoundError` (a lookup with no match returns `null` instead) |
| `409` | `ConflictError` |
| `410` | `GoneError` |
| `422` | `UnprocessableEntityError` |
| `429` | `RateLimitError`, or `DailyLimitError` for a daily limit |
| `451` | `UnavailableForLegalReasonsError` |
| `5xx` | `InternalServerError` |
| Any status with `KEY_CREDIT_LIMIT_REACHED` | `KeyCreditLimitError` |

A network failure raises `APIConnectionError`. An attempt that times out raises `APITimeoutError`, a subclass of `APIConnectionError`.

The SDK retries a request up to 4 times after the first attempt, 5 attempts in total:

- For a `429` from the per-minute rate limit, the SDK uses `error.details.retryAfter` as the delay, or the `Retry-After` header if that value is missing. Otherwise, the SDK backs off.
- For a `500`, `502`, `503` or `504`, the SDK uses exponential backoff: 2, 4, 8, then 15 seconds, plus up to 250 milliseconds of jitter. If the response includes `Retry-After`, the SDK uses that delay instead.
- If the requested wait exceeds 60 seconds, the SDK raises the error at once.
- A network failure or a timed-out attempt is retried on `GET` requests. A `POST` is retried only when the connection was never established, so a request the API may already have billed is never sent twice. Find Email, Verify Email and Find Phone are the exception, protected by their idempotency key (see below).

The SDK never retries `DailyLimitError` (daily limits, `DAILY_LIMIT_EXCEEDED` and `DAILY_EXTRACTION_LIMIT_EXCEEDED`), `KeyCreditLimitError` (an API key credit limit) or `InsufficientCreditsError`. Other `4xx` errors are not retried either, except per-minute `429` rate limits and `409 IDEMPOTENCY_KEY_IN_USE` for Find Email, Verify Email and Find Phone.

For a non-retryable error, change the request, key or account, or wait until the next day. Set `maxRetries: 0` to turn retries off.

**Handle errors**

```typescript [TypeScript SDK]
import ReverseContact, { APIError, DailyLimitError, KeyCreditLimitError } from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

try {
  await client.enrich.company({ domain: "acme.com" });
} catch (error) {
  if (error instanceof DailyLimitError || error instanceof KeyCreditLimitError) {
    // Not retried: pause the work until the limit resets.
    console.error("Limit reached:", error.code, "retry after", error.retryAfter, "seconds");
  } else if (error instanceof APIError) {
    console.error(error.status, error.code, error.message, "request id:", error.requestId);
  } else {
    throw error;
  }
}
```

[Error handling & retries](https://docs.reversecontact.com/guides/errors-retries) lists every error code of the API.

## Safe retries on Find Email and Find Phone

Sending the same Find Email, Verify Email or Find Phone request twice would start two jobs, and both can be billed. To prevent duplicate jobs on automatic retries, `contact.findEmail`, `contact.verifyEmail` and `contact.findPhone` send an `Idempotency-Key` header with a new UUID on each call. The SDK reuses that key on every automatic retry of the call. For 24 hours, repeating the same key and body returns the first response without starting or billing another lookup.

To retry safely after your process restarts, choose the key yourself, store it with the request, and pass it as `idempotencyKey`. `job.replayed` is `true` when the API returned the first response again.

**Idempotency key**

```typescript [TypeScript SDK]
import ReverseContact from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const job = await client.contact.findEmail(
  { fullName: "Jane Doe", companyDomain: "acme.com", emailType: "any" },
  { idempotencyKey: "crm-contact-4821-email" }
);
console.log(job.id, job.replayed ? "first response returned again" : "new lookup");

const done = await job.wait();
for (const email of done.data.result ?? []) console.log(email.value, email.type);
```

Use 1 to 255 printable ASCII characters without spaces, and a new key for each new lookup. If the key is empty, longer than 255 characters, or contains a space or non-ASCII character, the SDK raises `ReverseContactError` before sending a request.

The SDK retries `409 IDEMPOTENCY_KEY_IN_USE` after the delay in `Retry-After`. A `422 IDEMPOTENCY_KEY_REUSED` (same key, different body) and a `400 INVALID_IDEMPOTENCY_KEY` are not retried. After 24 hours, the same key can start and bill a new lookup. To read a job you already started, call `client.jobs.wait(id)`.

List creation and Bulk submission also generate keys. List imports generate an `operationId`. See [Lists and Bulk enrichment](https://docs.reversecontact.com/sdk/javascript/lists-and-bulk).

## Local validation and job errors

`ReverseContactError` also reports invalid SDK options, missing search budgets, repeated pagination cursors and malformed webhook envelopes. `JobTimeoutError` reports an expired wait deadline. `JobFailedError` reports a failed live-fetch or contact job from `job.wait()` or `client.jobs.wait()`. See [Async jobs](https://docs.reversecontact.com/sdk/javascript/async-jobs) and [Timeouts and cancellation](https://docs.reversecontact.com/sdk/javascript/timeouts).

Return to the [TypeScript SDK overview](https://docs.reversecontact.com/sdk/javascript).

## FAQ

### Which requests does the TypeScript SDK retry automatically?

The SDK retries per-minute rate limits and HTTP 500, 502, 503 and 504 up to 4 times after the initial attempt. Contact requests also retry HTTP 409 `IDEMPOTENCY_KEY_IN_USE`.

### Does the SDK retry daily or API key credit limits?

The SDK does not retry `DailyLimitError`, `KeyCreditLimitError` or `InsufficientCreditsError`. Change the request or account limits, or wait for the relevant reset.

### How do I retry Find Email safely after a restart?

Persist the request body and an `idempotencyKey`, then reuse both within 24 hours. For a job id already saved, call `client.jobs.wait()` to read the existing job.

### How do I disable automatic SDK retries?

Set `maxRetries: 0` on the client or on an individual request. Wait helpers use their own polling options, described in the Async jobs guide.
