Your first research run
The async job contract — create, poll, read results, retry safely
Research runs are asynchronous jobs: creating one returns immediately; the research itself takes minutes. Polling is the contract — never hold a connection open waiting.
Test mode — iterate for free
{"dry_run": true} behaves exactly like a real run — 202 + Location,
status: "running" — except it's free, instant to set up, and completes in
~15 simulated seconds. Poll the returned id like a real run; on completion it
carries sample rows + per-cell citations in your Blueprint's real shape
("test": true throughout). Nothing is billed, persisted, or researched.
Build your entire create → poll → parse loop against it first.
Create
curl -s -X POST $BASE_URL/v1/research/runs \
-H "Authorization: Bearer $DEEPSIEVE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"query": "European industrial-automation companies using AI vision"}'Send either query (a natural-language research intent) or
seeds (a list of URLs or names). Optional: guidance (steering text),
depth ("standard" | "max"), monitored (keep the results fresh after the
run; default true).
Response: 202 with a Location header and the run resource.
Always send Idempotency-Key
Runs bill real money. With an Idempotency-Key header, retrying the same
request replays the original response instead of starting (and billing) a
second run. Reusing a key with a different body is a 422; retrying while
the original is in flight is a 409 with Retry-After.
Poll
curl -s $BASE_URL/v1/research/runs/{id} -H "Authorization: Bearer $DEEPSIEVE_API_KEY"{"object": "research_run", "id": "…",
"status": "running", "done": false, "error": null,
"progress": {"phase": "investigate", "entities_found": 4, "entity_counts": {"companies": 4}},
"metrics": {"search_queries": 41, "sources_read": 12, "…": "…"}}status is a closed enum: queued | running | cancelling | completed | failed | cancelled. done: true means terminal. On failed, error.code /
error.message say why — a failed run is automatically refunded. Poll every
~15 seconds (the Retry-After header on non-terminal responses is the hint).
POST /v1/research/runs/{id}/cancel stops an in-flight run.
List
GET /v1/research/runs?limit=&cursor=&status= returns the standard list
envelope {"data": [...], "has_more": bool, "next_cursor": "…"}.
Read the results
Results land in your Blueprint's entity tables, not in the run object — see
Dataset sync. Webhooks fire on
run.completed / run.failed / run.cancelled if you'd rather not poll —
see Webhooks.