Before you start
- A connected LinkedIn account: every enrichment runs on one of your own accounts.
- The
can_act_linkedin_enrichmentpermission on your API key, agent or user. - One identifier:
profile_id(ACoAA...orACwAA...) orpublic_identifier(the vanity slug from/in/...). Exactly one, never both, or the call is422 validation_failed.
The two methods that return contact details
Both ride the same read but cache under their own key: a cached full profile does not
satisfy a contact-info call, and the reverse is also true.
Run it
curl
result.contact_info, next to the ledger row at
result.data_request (sid starting er_rq_, status, executed_on,
served_from_cache, cached_from_sid). Per-method shapes are in the
API reference, and batching is your own loop (no mass action,
no sequence step), one target per call.
contact_info is always present, and every field inside it can be empty. An empty block
means the connected account still cannot see those details, never that the call was
blocked. address, birthday and connection date are not parsed. A phone with
type: null is normal on older cached payloads, not a defect.
Which account runs the call
Every enrichment runs on one of your own connected accounts.Contact info is the exception
person-contact-info requires a connected executor: LinkedIn reveals contact details to
1st-degree connections only, so the pick is narrowed to accounts that actually hold the
edge.
Here
linkedin_account_sid is a preference, not a command: another connected account is
picked if the one you named does not qualify, and accounts out of budget, on hold or
LinkedIn rate-limited are dropped before the pick.
How long a result is cached
A repeat for the same person and method inside the TTL is served from the stored result
(
served_from_cache: true, nothing dispatched); past it, the call executes again. Cache
is per team, per method.
How to read a partial result
An empty answer is a real answer. A person who never published a phone number produces acompleted row with an empty field, not an error.
A row is inserted either
running or already terminal; running then moves to
completed, failed or rejected (a reservation failure rejects an already running
row).
A call has a hard deadline of 90 seconds; typical latency is 30 seconds at p95 executed,
500 ms at p95 cache-served. Retrying is safe when you reuse the idempotency_key; inside
that window the replay returns the running row, so poll GET /api/data-requests/{sid}
until the status is terminal. To follow results without polling, subscribe to the
data-requests.completed and data-requests.failed webhooks; the completed payload adds
result_ref and completed_at to the receipt fields. Refusals have no
event: a rejection appears only as the synchronous HTTP error.
Daily budget
Enrichment spends one shared bucket per account calledenrichment. Read it before a
batch, on the Smart Limits tab of the account drawer or through
smart limits and warmup filtered on limit_type.
Errors you will actually hit
bucket_saturated on a 429 is your own account’s daily enrichment budget, nothing wider.
Wait for retry_after, or pin a different connected account that still has budget.