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

bash
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

bash
curl -s $BASE_URL/v1/research/runs/{id} -H "Authorization: Bearer $DEEPSIEVE_API_KEY"
Response· json
{"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.

Your first research run — DeepSieve API