Async Polling
Retrieve the status and results of asynchronous jobs.
Webhook delivery is the primary path for async search/enrichment results. Polling is the fallback when your webhook receiver is unavailable, when you need to fetch results out-of-band, or for debugging.
Outreach Emails are the exception: they require no webhook secret and are designed to be polled — GET /api/public/v1/emails/{id}/ is the live resource itself (not a job wrapper), so everything below about dj_ jobs doesn't apply to em_ emails. See Outreach Emails. While drafting, poll every 5–10 seconds; drafts typically complete in 10–60 seconds.
#Polling URLs
Use the job id returned by the original POST (e.g. dj_a1b2c3d4...):
| Endpoint | Polling URL |
|---|---|
| People Search | GET /api/public/v1/search/{job_id}/ |
| Deep Search | GET /api/public/v1/deep-search/{job_id}/ |
| Agentic Search | GET /api/public/v1/agentic-search/{job_id}/ |
| Phone Enrichment | GET /api/public/v1/enrich/phone/{job_id}/ |
Polling does not consume credits.
#Response shape
{
"id": "dj_a1b2c3d4...",
"status": "completed",
"tier": "light",
"created_at": "2026-05-02T06:39:06.013878Z",
"started_at": "2026-05-02T06:39:06.079964Z",
"completed_at": "2026-05-02T06:39:42.009761Z",
"leads_returned": 25,
"result": { ... },
"error": null
}#Field reference
| Field | Type | Notes |
|---|---|---|
id |
string | dj_<32-hex> job identifier. |
status |
string | One of pending, running, completed, failed, cancelled. |
tier |
string | One of light (People Search), deep_standard, deep_extended (Deep Search), agentic_search, phone_enrich. |
created_at |
ISO 8601 | When the job was accepted. |
started_at |
ISO 8601 or null |
When the worker picked it up. |
completed_at |
ISO 8601 or null |
When the worker reached a terminal state. |
leads_returned |
int | Final lead count. 0 until terminal. |
result |
object or null |
Populated only when status == "completed". |
error |
object or null |
Populated only when status is failed or cancelled. |
#result shape (when completed)
The result object carries the same body the webhook would have delivered — minus the id / event_type wrapper. Schemas:
- People Search:
{results: [...], total_returned: int} - Deep Search:
{results: [...], total_returned: int} - Agentic Search:
{results: [...], total_returned: int, partial: bool, completion_reason: string} - Phone Enrichment:
{phone: string | null}
Per-lead and per-field shapes are documented under Webhook Events.
#error shape (when failed or cancelled)
{"code": "error", "message": "..."}Codes and messages are the same as the webhook *.failed events — see Webhook Events for the per-endpoint tables.
#Status lifecycle
pending → running → completed
→ failed
→ cancelledpending is the initial state right after the POST returns 202. The worker transitions it to running when it picks up the job, then to one of the three terminal states.
Agentic Search can also move directly from pending to cancelled. Cancelling a running Agentic Search normally finishes as completed with result.partial: true and result.completion_reason: "user_cancelled". Always inspect the result's partial flag when processing completed Agentic Search jobs.
#Polling cadence
Reasonable defaults:
- People Search: poll every 5–10 seconds. Typical run completes in 15–30 seconds.
- Phone Enrichment: poll every 10-15 seconds. Typical run completes in 1 minute.
- Deep Search: poll every 30–60 seconds. Typical run completes in 10–15 minutes.
- Agentic Search: poll every 30–60 seconds until terminal; duration depends on the research brief and budget.
Polling endpoints have a high rate cap (3600/min) so brief tight-loop polling will not throttle.
#Wrong job ID
A GET against an unknown or malformed job_id returns 404 not_found in the canonical envelope.
#See also
- Webhook Events for the inner result shape and per-endpoint payloads.
- Webhook Signing Secrets and Webhook Signature Verification for the primary delivery path.
- Idempotency for replaying without double-dispatch.