SDKs
Python SDK (generated, typed, sync+async) — TypeScript next
Python
pip install deepsieveFully typed, sync + async, generated from the /v1 contract:
from deepsieve import SDK
with SDK(bearer_auth="ds_live_...") as sdk:
me = sdk.v1_meta.v1_meta_get_me().result
# Free test run — exercises the real poll loop
run = sdk.v1_research.v1_research_create_run(query="...", dry_run=True).result
# Discover the schema, then read cited data
catalog = sdk.v1_data.v1_data_data_catalog().result
page = sdk.v1_data.v1_data_read_entity_data(
entity_key=catalog.entities[0].key, receipts=True
).resultChange history
From deepsieve 0.3.4, the SDK carries the two lineage reads. One is the
log of a column across records; each entry carries a persistent cell_id,
which the other takes to return every value that one cell has ever held:
bp = sdk.v1_blueprints.v1_blueprints_list_blueprints().result.data[0]
log = sdk.v1_lineage.v1_lineage_read_column_changes(
blueprint_id=bp.id, entity_key="companies", column="headcount"
).result
first = log.data[0] # first.change_kind: initial | changed | unchanged | amended | observed | unknown
# amended: QA corrected the value in place; first.pre_amend_kind / first.pre_amend_value say what it replaced
history = sdk.v1_lineage.v1_lineage_read_cell_changes(
cell_id=first.cell_id, include="rechecks"
).resultBoth are keyset-paged newest first; keep next_cursor to resume, and read
truncated before treating a page as complete on a free-preview account.
Merges, renames and successor links
v1_changes.v1_changes_list_changes returns them newest first, and
v1_changes.v1_changes_undo_change undoes one (data:write, member role). Pass
idempotency_key so a retry is safe:
page = sdk.v1_changes.v1_changes_list_changes(live=True).result
change = page.data[0] # change.kind: merge | renamed | succeeded_by
if change.undoable:
sdk.v1_changes.v1_changes_undo_change(
change_id=change.id, idempotency_key=f"undo-{change.id}"
)Cells a person set on purpose
v1_holds.v1_holds_list_holds(pending=True) lists the cells research will not
overwrite, each with the pending_finding it found since.
v1_holds.v1_holds_apply_cell_finding takes one (pass the finding_evidence_id
your human saw; a newer one since is refused finding_changed),
v1_holds.v1_holds_keep_cell_value keeps your human's value and dismisses it (same
argument; research does not ask again unless it cites a new page), and
v1_holds.v1_holds_release_cell stops protecting the cell. All three need
data:write and the member role:
page = sdk.v1_holds.v1_holds_list_holds(pending=True).result
for cell in page.data:
print(cell.column, cell.value, "->", cell.pending_finding.value)Marking rows as duplicates
v1_merges.v1_merges_preview_merge writes nothing; v1_merges.v1_merges_create_merge
takes the same body plus the preview's preview_digest, so it applies exactly the
merge you previewed. If anything changed since, the merge is refused merge_changed
with the merge as it stands now (and its own digest) in the error's details, and
nothing is written. To merge without a preview, pass apply_without_preview=True;
passing neither is preview_required. Settle every tie in choices (the preview
lists unresolved_ties), or the merge is refused ties_unresolved. Rows under
different parents (an entity unique per parent) are refused
merge_across_parents: merge only within one parent. Two rows' lists of links are
combined, never a tie: the preview says how under links_combined.
After a run starts (0.5.0)
These need deepsieve 0.5.0 or later:
v1_research.v1_research_retry_runretries a failed, stopped or empty run. A retry that would charge is refusedretry_confirmation_requiredwith the quote indetails; ask your human, then call again withexpected_total_centsset to that total.v1_research.v1_research_get_rerunsandv1_research_approve_rerunsread and approve a report's waiting re-research, against thequote_idand total you were shown.v1_research_set_reruns_auto_approveturns automatic approval on (with a monthly cap) or off; on is standing authority to spend, so ask first.v1_research.v1_research_set_monitoringturns a report's monitoring on or off, andv1_research_list_monitoringshows what monitoring costs across a Blueprint.v1_links.v1_links_remove_linkremoves a wrong link; research will not add it back.
Runs has the rules each one follows.
Domain knowledge and conflicting values (0.8.0)
These need deepsieve 0.8.0 or later:
v1_knowledgelists, adds, edits, retires, restores and removes a Blueprint's domain knowledge, andv1_knowledge_knowledge_usageshows how each entry was used across recent runs. Writes need theknowledge:writescope.v1_blueprintshas the same calls for a Blueprint still being created (v1_blueprints_list_draft_knowledgeand its siblings), and a follow-up answer can carryskipfor thedomain_knowledgequestion. Ask your human before you skip it.v1_research.v1_research_get_run_knowledgeshows what knowledge a run carried and what it decided.v1_holds.v1_holds_list_conflictslists the cells a run stated more than one way, andv1_holds_choose_cell_valueshows the value your human chose.
Changelog has the details of each.
Merged lists, closed accounts and search counts (0.9.0)
These need deepsieve 0.9.0 or later:
- A list cell a run stated more than one way can read
selection.statemerged, withselection.itemssaying which version stated each item and its sources. Each entry fromv1_lineage.v1_lineage_read_cell_changesandv1_lineage_read_column_changescarries its ownselection. v1_meta.v1_meta_get_me'ssubscriptioncarriesexpired_from_plan,expired_from_plan_labelandretention_until, so a closed or expired account no longer reads as a new one. Checkexpired_from_planfirst.- A run's
metrics.search_queriesis typed as nullable:Nonemeans not reported, never zero searches.
Changelog has the details of each.
Name the Blueprint
v1_research_create_run, v1_research_estimate_run and
v1_webhooks_create_webhook need blueprint_id (an id from
v1_blueprints_list_blueprints). The signature marks it optional only so that a
dry_run=True call can leave it out; any other call without it is refused by the
API with 400 invalid_request and param: "blueprint_id", before anything is
charged.
Enforced sources
v1_research_create_run and v1_research_estimate_run take
allowed_sources, a list of hosts, wildcard suffixes, URL prefixes or
blueprint:primary. The run refuses to write any cell it cannot cite from that
list, and the run resource echoes the resolved list it enforced.
Every call returns .result (typed models) plus .headers (RateLimit-*,
X-Request-Id). Errors raise typed exceptions carrying the same
{code, retriable, request_id} envelope the REST API returns.
The SDK is generated from /openapi.json's /v1 subset and
regenerated whenever the contract changes, and CI fails a PR that leaves the
two out of step. That keeps the SDK matching the CONTRACT; where the contract
and the running API disagree, the API is the truth and the gap is our bug.
TypeScript
Next up, generated from the same source. Until then the REST API is
deliberately easy to consume raw — every list is {data, has_more, next_cursor}, every error is typed — and your coding assistant can build a
thin client from the Quickstart prompt block in one shot.