Skip to main content
Each -async endpoint, and each Bulk Intelligence submission, starts a job and returns its task_id at once. GET /job-status/{task_id} reports the job’s status and, once it completes, its result.
Start response
A start response carries task_id and an uppercase status, RUNNING for a new job. Some endpoints add fields, such as unrecognized_fields, investigation, total_leads, mode or estimated_cost_credits. Job status reports statuses in lowercase. The format of task_id varies by endpoint, so store it exactly as returned. Age Verification jobs report their status at GET /verify-age/{task_id} instead.

Job status

Completed job

Statuses

running is the only status in progress: every other status is final. A single-record job that ends failed returns its held credits, but paid source tasks an Atlas run already started are still charged. An Atlas run (xhigh, or scout with graph) that the agents decline still reports completed: its notes start with Declined:, structured_data repeats the input, and nothing is charged. Check notes before you store structured_data. See Declined runs.

Results by job type

Find Email reports find_email, Find Phone reports find_phone, and Reverse Email and Reverse Phone both report reverse_enrichment.

Contact lookups in job status and webhooks

A single-lead contact job returns the lead itself in job status. Its webhook callback wraps the lead in result.leads, with the totals:

Polling

  • Poll each job every 10 seconds or slower. Job status is cached for up to 10 seconds: a new status shows on the next request, but other fields, such as bulk progress, refresh at most every 10 seconds.
  • API keys and OAuth clients share one polling budget per organization: 300 requests a minute with a burst of 15, counted across GET /job-status/{task_id} and workflow live status. At one request per job every 10 seconds, the budget covers about 50 jobs at once. Signed-in sessions in the Sixtyfour app do not count against it. See Rate Limits.
  • Past the budget, job status returns 429 with a Retry-After header and X-RateLimit-Requests, X-RateLimit-Period and X-RateLimit-Burst headers. A 503 with Retry-After means status is briefly unavailable. Either way the job keeps running: wait Retry-After seconds and poll again, without restarting the job.
  • To follow many jobs, poll them from one loop that stays within the budget, or pass webhook_url and poll only the jobs whose callback is late.
This example waits for one job and honors Retry-After:

Webhooks

Pass webhook_url to receive the result by POST instead of polling. Outgoing Webhooks documents the payload, signing and retries. Callbacks relate to job status as follows:
  • A callback is sent before the job closes, so job status can still read running briefly after the callback arrives.
  • People Intelligence, Company Intelligence and QA Agent send the callback as soon as research finishes, before the job’s charge is settled. The callback carries no charge: read charge_credits from job status once it reads completed. These three also send the callback from their sync endpoints when the request has a webhook_url.
  • Contact lookups send the callback after the charge, so result.cost_credits is final. Their result differs from job status; see Contact lookups in job status and webhooks.
  • Bulk Intelligence sends a workflow run payload whose run_id equals the task_id. See Bulk Intelligence.
  • Only completed jobs send a callback. If none arrives by your deadline, poll job status.
  • A job retried after its callback went out sends another, with a new event_id. Deduplicate callbacks on task_id.

Sync calls and retries

A sync endpoint runs the same job and waits for it. If your client times out or disconnects, the job keeps running and is charged when it finishes, and a retry starts and charges a second job.
  • Use the async endpoint for long research. A sync People Intelligence, Company Intelligence or QA Agent call that waits more than 90 seconds for capacity returns 503 and is not charged; the async job waits up to 24 hours.
  • To make an async start safe to retry, send dispatch_id (8 to 128 characters) to POST /people-intelligence-async or POST /qa-agent-async. A repeat with the same dispatch_id in your organization returns the original job’s task_id with status: "RUNNING", and starts and charges nothing. This holds even after the original finished, for as long as it is retained, and even when the body differs. Poll the task_id for the job’s actual status. Keys share one namespace across People Intelligence, QA Agent and the Atlas API’s start and continue routes, so a reused key returns the first job even when the request names another investigation.
  • Company Intelligence and the contact lookups take no dispatch_id, so a repeated start runs and charges again. A dispatch_id sent to POST /company-intelligence-async comes back in unrecognized_fields.
  • Bulk Intelligence takes an Idempotency-Key header. See Bulk Intelligence.

Retention

Job status is not long-term storage: save each result when its job completes.

Errors

For error responses (404, 429, 503, etc.), see Handling Errors.