Skip to main content
People search, enrichment, and outreach. Get started with the clodo API
Guides

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
                  → cancelled

pending 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

clodo Docs