Skip to content

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

SDKs // Python // Guides

Errors and retries

Last verified

Handle Python SDK exceptions, understand automatic retries and rate limits, and reuse idempotency keys safely for Find Email and Find Phone.

SDK-defined errors inherit from ReverseContactError. If a response cannot be parsed into the declared model, Pydantic can also raise ValidationError. Errors returned by the API inherit from APIError, with status, code, message, details, request_id, retry_after, headers and body.

HTTP statusError class
400BadRequestError
401AuthenticationError
402InsufficientCreditsError
403PermissionDeniedError
404NotFoundError (a lookup with no match returns None 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. If an attempt runs out of time, the SDK raises APITimeoutError, a subclass of that error.

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 first checks error.details.retryAfter for the retry delay, then the Retry-After header. If neither supplies a delay, the SDK backs off.
  • For a 500, 502, 503 or 504, the SDK backs off exponentially: 2, 4, 8, then 15 seconds, plus up to 250 milliseconds of jitter. If the response sends Retry-After, the SDK uses that delay instead.
  • If the requested wait exceeds 60 seconds, the SDK raises the error at once instead of waiting.
  • The SDK retries network failures and timed-out attempts on GET requests. For a DELETE, the SDK also retries a transport failure when no HTTP response was received. For a POST, the SDK retries only when the connection was never established. This prevents sending a request twice when the API may already have billed it. Find Email and Find Phone are exceptions, protected by their idempotency key (see below).

The SDK never retries DailyLimitError (the 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 409 IDEMPOTENCY_KEY_IN_USE for Find Email and Find Phone. To resolve these errors, change the request, key or account, or wait until the next day. Set max_retries=0 to turn retries off.

Python SDK

Handle errors

import os

from reversecontact import APIError, DailyLimitError, KeyCreditLimitError, ReverseContact

with ReverseContact(api_key=os.environ["RC_API_KEY"]) as client:
    try:
        client.enrich.company(domain="acme.com")
    except (DailyLimitError, KeyCreditLimitError) as error:
        # Not retried: pause the work until the limit resets.
        print("Limit reached:", error.code, "retry after", error.retry_after, "seconds")
    except APIError as error:
        print(error.status, error.code, error.message, "request id:", error.request_id)

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. contact.find_email, contact.verify_email and contact.find_phone send an Idempotency-Key header with a new UUID on each call. Each automatic retry of that call reuses the key. For 24 hours, the API returns the first response for a repeated key and body, 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 idempotency_key. job.replayed is True when the API returned the first response again.

Python SDK

Idempotency key

import os

from reversecontact import ReverseContact

with ReverseContact(api_key=os.environ["RC_API_KEY"]) as client:
    job = client.contact.find_email(
        full_name="Jane Doe",
        company_domain="acme.com",
        email_type="any",
        idempotency_key="crm-contact-4821-email",
    )
    print(job.id, "first response returned again" if job.replayed else "new lookup")

    done = job.wait()
    emails = done.data.result if done.data and done.data.result else []
    for email in emails:
        if email is not None:
            print(email.value, email.type)

Use 1 to 255 printable ASCII characters without spaces, and a new key for each new lookup. A key that is empty, longer than 255 characters, or contains a space or a non-ASCII character raises ReverseContactError before any request is sent.

The SDK retries 409 IDEMPOTENCY_KEY_IN_USE after its Retry-After delay. The SDK does not retry 422 IDEMPOTENCY_KEY_REUSED (same key, different body) or 400 INVALID_IDEMPOTENCY_KEY. After 24 hours, the same key can start and bill a new lookup. To read a job you already started, call client.jobs.wait(job_id).

List and Bulk retry identifiers

lists.create() and bulk.enrich_persons() generate an Idempotency-Key when you omit one and reuse that key on automatic retries. lists.import_signals() generates an operation_id when omitted. Save your own identifiers to continue the same work after a restart. See Lists and Bulk enrichment.

These methods do not use the contact endpoints' special retry rule for ambiguous POST transport failures or 409 IDEMPOTENCY_KEY_IN_USE. Use client.contact for the three contact methods protected by that rule.

APIError also exposes http_response, alternative and reset_at. KeyCreditLimitError adds period, limit, used and required. See Timeouts and cancellation for HTTP and overall job deadlines.

Return to the Python SDK overview.

FAQ

Does the reversecontact Python SDK retry failed requests?

The SDK retries per-minute rate limits and HTTP 500, 502, 503 and 504 up to four times by default. Daily limits, key credit limits and insufficient credits are not retried.

How do I disable automatic retries in Python?

Pass max_retries=0 to the client or an individual API method. That setting disables the request transport's automatic retries.

How do I retry Find Email without creating another job?

Store a request-specific idempotency_key and reuse that key with the same body. Contact endpoints return the first response for 24 hours. Check job.replayed to identify a replay.

Which Python exception represents an invalid API key?

An HTTP 401 response raises AuthenticationError, a subclass of APIError and ReverseContactError. Inspect request_id, status, code and message for diagnostics.