Async job model
BetaUnderstand the job lifecycle, progress events, and how to poll incrementally.
Beta
Job lifecycle
Every submission creates a job that moves through a small set of states:
| Status | Meaning |
|---|---|
queued | Accepted and waiting to start. This is always the status of the submit response. |
running | Background research is in progress. |
completed | Finished successfully. The full result is in response. |
failed | The job stopped with an error. See error. |
completed and failed are terminal — stop polling once you see either.
Polling with a cursor
GET /v2/risk/{job_id} returns the current status, any new progress events, and a cursor. The cursor is the sequence number of the most recent event in the response.
To avoid re-reading events you already have, pass the last cursor you saw as the after query parameter:
GET /v2/risk/{job_id}?after=0
Each response only contains events newer than after, so a typical loop is: poll, apply the new events, remember cursor, repeat with after=cursor.
Running (incremental events)
Progress events
Events let you show live progress. Each event has a type, an ISO timestamp, and elapsed_ms since the run started:
| Event type | Emitted when |
|---|---|
run_started | The run begins; includes stages and requested_categories. |
stage_started | A pipeline stage begins (for example, research). |
stage_completed | A stage finishes; includes duration_ms. |
stage_error | A stage reported an error; the job may still continue. |
category_started | Work on a specific category begins (category_id). |
category_completed | A category finishes; includes its status. |
run_completed | The run succeeded; includes entity_id. |
run_failed | The run failed; includes an error reason. |
You can treat events as a presentational stream — the authoritative outcome is always the top-level status and response.
Completion and failure
When status is completed, the poll payload carries the full risk result under response, plus top-level entity_id and snapshot_id for the stored record. Inside response, categories are grouped under categories (not a flat top-level list), summary is top-level, and provenance lives in sources with per-category source_ids references — see the API reference.
When status is failed, response is absent and error describes what went wrong.
Cancel
POST /v2/risk/{job_id}/cancel stops an in-flight job, marks it failed, and refunds unused credits. If the job is already terminal, the call is safe to retry and refunded_credits is 0.
POST /v2/risk/{job_id}/cancel
Best practices
- Poll every 2–3 seconds. Research takes minutes, not milliseconds; tight polling adds load without value.
- Always send
after. It keeps responses small and your event handling idempotent. - Stop on terminal status. Never keep polling a
completedorfailedjob. - Persist the
job_id. Use it to resume polling after a restart, match webhook deliveries, or cancel. - Send
Idempotency-Keyon submit if your client may retry the same company. Retries reuse the original job and do not charge again.