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 status | Error class |
|---|---|
400 | BadRequestError |
401 | AuthenticationError |
402 | InsufficientCreditsError |
403 | PermissionDeniedError |
404 | NotFoundError (a lookup with no match returns None 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. 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
429from the per-minute rate limit, the SDK first checkserror.details.retryAfterfor the retry delay, then theRetry-Afterheader. If neither supplies a delay, the SDK backs off. - For a
500,502,503or504, the SDK backs off exponentially: 2, 4, 8, then 15 seconds, plus up to 250 milliseconds of jitter. If the response sendsRetry-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
GETrequests. For aDELETE, the SDK also retries a transport failure when no HTTP response was received. For aPOST, 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.
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.
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.