Skip to main content
A job runs a search, enrichment or export asynchronously. Reach for one when the work exceeds what a synchronous call will do: more than 100 enrichment inputs, more than 1,000 search results, or any export to a file.

Creating a job

The response returns immediately:
Always send an Idempotency-Key when creating a job. A job is the one place where a retried request costs real money twice — see Idempotency.

The three job types

Takes the same body as POST /enrich, with either an inputs array or an inputs_url pointing at a JSONL file of inputs — one object per line, same shape as a synchronous input.
Takes a search body with no limit or cursor, and returns the full result set past the 1,000-row synchronous depth by sharding the query for you.
Takes entity, format (csv or jsonl) and a search body. Produces a file rather than paginated JSON.

Collecting the result

Subscribe to job.completed and let the webhook tell you. Polling is the fallback, not the plan.
For enrich and search jobs, read the output from GET /jobs/{id}/results — cursor-paginated like any other list. For export jobs the job itself carries a signed download_url, valid for 24 hours; results returns 409 for them.

Statuses

partially_completed is a success with holes, and it is the status most often mishandled. Read progress.failed, pull the results, and reconcile against your inputs by ref — do not assume a completed job returned a row for everything you sent.

Cancelling

Cancelling stops a queued or running job. Work already completed is still charged, and results produced so far remain readable. A job that has already finished returns 409.

Practical limits

Jobs past the concurrency limit stay queued rather than failing, so a nightly batch that overruns will drain rather than drop.