Skip to content

MaintenanceThe former company search endpoint goes into maintenance on November 9Migration guide

SDKs // TypeScript // Guides

Errors and retries

Last verified

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

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 statusError class
400BadRequestError
401AuthenticationError
402InsufficientCreditsError
403PermissionDeniedError
404NotFoundError (a lookup with no match returns null instead)
409ConflictError
410GoneError
422UnprocessableEntityError
429RateLimitError, or DailyLimitError for a daily limit
451UnavailableForLegalReasonsError
5xxInternalServerError
Any status with KEY_CREDIT_LIMIT_REACHEDKeyCreditLimitError

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.

TypeScript SDK

Handle errors

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 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.

TypeScript SDK

Idempotency key

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.

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 and Timeouts and cancellation.

Return to the TypeScript SDK overview.

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.