Integration best practices
Everything on this page is optional - the API works fine call-by-call. But these are the patterns that separate an integration that is fast, cheap and robust from one that burns credits and retries blindly. If you are building an automated integration or an AI agent on top of the API, start here.
Retries and idempotency
Every v2 endpoint uses POST, but do not let the verb mislead you:
- Search endpoints are read-only. People Search, Company Search and Enums never change anything and never spend credits - retry them freely.
- Enrich endpoints are safe to retry too. Revealing an email or phone your workspace already unlocked is free, so replaying a successful People Enrich or Email Finder call does not double-charge you.
- Follow the per-status guidance on Errors: retry
408after a few minutes and5xxwith exponential backoff; never retry400,401or402unchanged - they will fail the same way again.
Do not guess names or values
Request bodies are strictly validated: an unknown field anywhere in the
body fails the whole request with 400 rather than being ignored. The two
bulk endpoints are the one exception - an unknown field inside an item
moves that item to the invalid bucket instead of failing the batch.
Enum-backed filters accept exact, case-sensitive values only. Read them
from Enums (or GET /v2/enums at integration time)
instead of inventing close-enough strings - "vp" matches nothing,
"VP" does. The full request and response shapes are machine-readable in
the OpenAPI specification, and every docs page
has a markdown twin (append .md to its URL) indexed in
llms.txt.
Control your spend
Searching is free; credits are only spent when contact data is revealed. The cheap pattern is always: search broadly, reveal narrowly.
- Search with
enrich_emailoff (the default on search). Every result already includeshas_emailandemail_statusfor free. - Narrow to the people worth paying for - for example, filter
contact_details.email.statustovalidso you only ever reveal addresses that exist. - Reveal on the final subset only: re-run the narrowed search with
enrich_email: true, or enrich the shortlist via People Bulk Enrich. - Have a list of LinkedIn URLs? Look them up for free first with
People Search's
person.linkedin_urlfilter and only enrich the people it returns. - When the balance hits zero, credit-gated endpoints return
402 Payment RequiredwithX-Limit-Reached: true- treat that as a hard stop, not a retryable error.
Prefer bulk endpoints over loops
Enriching a list by looping the single endpoints works, but
People Bulk Enrich and
Company Bulk Enrich do up to 50 lookups
per request, keep partial failures contained (one bad item never fails the
batch), and echo your identifier on every outcome so results correlate
back to your rows without guesswork.
Pagination and result caps
Search results come 25 per page by default and up to 100 with per_page;
a query reaches 25,000 results either way (page 1000 at 25 per page, page
250 at 100). Follow the stop conditions on Pagination,
and if a search reports more matches than the cap, tighten the filters and
run several narrower queries (for example, split by country or headcount
range) rather than trying to page past the window.
Pacing
Real API keys have no hard rate limit today - the practical limit is your
credit balance. Still, keep concurrency modest (a handful of requests in
flight), let the bulk endpoints replace request storms, and back off on
5xx instead of hammering.
