Skip to main content
Plenty of calls in this API start work rather than finish it. They answer 202 Accepted with a handle, and the work lands over the following seconds or minutes. There is no single poller. The handle you get back tells you which one to use, and they are not interchangeable — this page maps them.

What 202 means

A 202 means the request was accepted and validated, not that the work succeeded. Two things follow from that:
  • Credits are usually spent by the background work, not the call. A 202 is not a receipt.
  • Failure arrives later. A job can accept cleanly and then fail per row, or find nothing at all.
Most calls that answer 200 or 201 have already finished by the time you read it. One exception: POST /business/campaigns answers 201 with status: "initializing", and an AI-generated campaign keeps preparing its steps in the background.

Which handle to poll

GET /business/jobs/{jobId} serves CRM async jobs and enrichment jobs — the 24-character hex ids. An import commit returns a UUID, which that endpoint refuses with 422. Follow an import through its destination list instead. A Data API job’s jobId is 24-hex too, but only GET /business/data/people/enrich-jobs/{jobId} serves it.

Following a list that is filling

Saving a search without enrichment, committing an import, copying rows and deriving a company list all work the same way: the list exists immediately and fills in the background. Read the list and watch completionStatus. When enrichment is involved, follow its job instead, because the list only turns processing once the job starts.
Row counts climb while it runs, so a list that reports rows is not necessarily finished.

Following a job

The smart-column status poller reports progress and what the run has spent so far:
failedRows is worth reading on every poll. A job can complete with failures — those rows simply have no answer — and nothing else will tell you.

Following an enrichment job

Enriching a list, or saving a search with enrich set, starts an enrichment job. Its poll at GET /business/jobs/{jobId} has type: "bulk_enrichment" and also carries the lists the run fills and its counts so far:
Stop polling on completed, cancelled or failed. A stopped job only moves again after a resume in the app, so poll it rarely, if at all.

Following a research run

Research runs report a stream of events rather than a percentage, because the interesting part is what the run is doing:
Each event carries a seq. Pass the last one you saw as sinceSeq on the next call to get only what is new, and stop when the run’s status is terminal.

How often to poll

Every poll counts against your rate limit, and several families share one bucket. A few rules that keep you inside it:
1

Wait before the first poll

Nothing meaningful has happened one second after a 202.
2

Back off as it runs

A few seconds apart early, then widen. Long jobs rarely need per-second resolution.
3

Use the cursor where there is one

sinceSeq on research events returns only new events instead of the whole history.
4

Stop on a terminal status

Poll a finished job and you are spending rate limit on a fixed answer.
On 429, wait for the window named in the response headers rather than retrying immediately.