Research runs

Statuses, retries, refunds, depth, and monitoring — the run lifecycle in full

Base URL + auth as everywhere: Authorization: Bearer ds_live_....

Lifecycle

queued → running → completed | failed | cancelled (with cancelling between a cancel request and its terminal state). The enum is closed — build exhaustive matches safely.

  • completed — results persisted with citations; run.completed webhook fires.
  • failederror.code/error.message on the resource; the run charge is automatically refunded; run.failed webhook fires. Don't blindly re-create — read the message first.
  • cancelled — partial results may exist; the charge stands (work was done).

Cost & latency

A run bills prepaid credits when it starts (typically $10 standard / $20 max depth — see pricing, or /billing for your own account) and takes 15-60 minutes.

One run researches one topic area and fills your Blueprint with what it finds. How many rows that yields depends on the area, so don't budget from an entity count — price the specific run:

bash
curl -s -X POST $BASE_URL/v1/research/runs/estimate \
  -H "Authorization: Bearer $DEEPSIEVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "solid-state battery startups in Japan", "depth": "standard"}'

Your first real run is free (one per account, before you subscribe) and isn't consumed if it fails.

Failed runs are refunded automatically; cancelled runs are charged (work was done). Spending is capped by the prepaid balance and any per-key budget — an agent can hit 402, never an invoice.

Top up a report instead of re-running it

If you already have a report and want to extend it, pass additive_to rather than starting a fresh run. Entities that report already holds with in-TTL evidence are dropped before the run is batched, so you pay for the gap, not the list — re-sending 20 held seeds plus 6 new ones costs about the 6. There is no cap on how many seeds you send: price scales with the list, so a longer one simply costs more and you approve it first.

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 '{"seeds": ["newco.example", "otherco.example"],
       "additive_to": "<existing_run_id>"}'

This is the right shape for a recurring loop — a quarterly refresh, a watchlist you keep topping up. Without it, re-sending the full list starts a new run that re-researches, and re-charges for, everything you already had. 404 means that id isn't a run in your workspace.

Price it first. additive_to works on /runs/estimate too, and it narrows the list exactly the way the charge does — so the quote is the gap, not the list you sent:

bash
curl -s -X POST $BASE_URL/v1/research/runs/estimate \
  -H "Authorization: Bearer $DEEPSIEVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"seeds": ["newco.example", "otherco.example"],
       "additive_to": "<existing_run_id>"}'

The response carries skipped_already_held when anything was dropped — that is why the number is lower than the list you sent, and worth logging so a surprise looks like an explanation rather than a bug.

Reuse what we already have

If the workspace already holds current data on some of your seeds, you can keep it instead of paying to research those entities again:

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 '{"seeds": ["acme.example", "newco.example"], "reuse_existing": true}'

Entities we already cover with in-TTL evidence are carried into the new report as they stand, with their sources, and cost no run credit. Anything stale is researched again regardless — reuse never passes off out-of-date data as current. The skipped entities come back as reused_existing so a cheaper run than your seed list implies is explained rather than mysterious.

This is the lineage-free sibling of additive_to: use reuse_existing when you just want whatever we have, and additive_to when you specifically mean "extend that report".

Depth

"depth": "standard" (default) or "max" — max lifts research budgets and uses the deeper agent preview; it costs more per run.

Monitoring

"monitored": true (default) keeps the run's target re-verified after the initial research, on a paid plan: every report is covered for its first 30 days, then while monitoring stays on. That is the "living dataset". Your plan keeps a set number of units fresh at no charge; each unit beyond that allowance bills per day (see pricing for your plan's rate, or /billing for your account).

The unit is a DOSSIER, not a report — one Deep Research call's returned data. A 20-entity request is researched as 4 dossiers, so it is 4 run credits AND 4 monitoring units, even though it reads as one report. Budget for the second number as well as the first: it is the recurring one. When a monitored value is re-verified and changes, a dataset.updated webhook fires with the record/column/evidence ids. Toggle per target later in the app.

See everything you're paying to monitor

An agent that creates reports on a schedule is the caller most likely to accumulate overlapping monitoring: re-researching a watchlist into a fresh report, rather than topping up the old one, is the natural loop — and it silently doubles the recurring cost. GET /v1/research/monitoring is how you audit that in one call.

bash
curl -s $BASE_URL/v1/research/monitoring \
  -H "Authorization: Bearer $DEEPSIEVE_API_KEY"
json
{
  "object": "monitoring_overview",
  "monitored_units": 12,
  "billing_units": 8,
  "duplicated_units": 4,
  "reports": [
    {"run_id": "…", "label": "EU vendors", "units": 4, "entities": 20,
     "in_free_window": false, "free_until": "2026-07-30", "billing": true,
     "fully_covered_by": ["<other_run_id>"]},
    {"run_id": "…", "label": "Watchlist", "units": 4, "entities": 18,
     "in_free_window": true, "free_until": "2026-09-04", "billing": false,
     "fully_covered_by": []}
  ],
  "warnings": [{"level": "INFO", "code": "monitoring_fully_duplicated", "…": "…"}]
}

Three things worth wiring into a scheduled job:

  • in_free_window and billing are separate flags, not one status. The first means the report is inside its free 30 days and costs nothing yet (free_until is the date that ends); the second means it is past that and spending units daily. The word "monitored" hides that difference, and it is the difference that shows up on an invoice next month.
  • fully_covered_by lists reports whose in-TTL entity set is a superset of this one's — everything here is already kept fresh there, so these units buy nothing. Only reported for reports actually billing.
  • billing_units vs monitored_units is what you are charged for versus what you are watching. duplicated_units is the gap you could reclaim.

Advisory only: warnings carries INFO entries and nothing is turned off on your behalf. Deciding which report keeps the coverage is a judgement call about which one your pipeline reads from, and we won't guess it.

Attribution & budgets

Runs created with an API key record that key (api_key_id) for audit and budget purposes. Keys can carry budget_runs/budget_cents ceilings — exceeding one returns 402 budget_exceeded.

Questions about a finished run

Ask the research agent directly — see Chat with the research agent. Your questions appear in the customer's own chat history for that report, attributed to your API key.

Research runs — DeepSieve API