Changelog

API changes, newest first

2026-09-16 — the cost estimate now accounts for the free run

affordable changes value for trial accounts. If you branch on it, read this.

POST /v1/research/runs/estimate priced a run against plan credits and prepaid dollars only. An unsubscribed org with its one free run unspent was therefore quoted affordable: false with a shortfall_cents — and then POST /v1/research/runs succeeded and charged nothing, because the free run funds it. An autonomous caller obeying the estimate halted before reaching a run it could in fact have made.

WasNow
affordable: false, shortfall_cents: 1000affordable: true, shortfall_cents: 0

New on the estimate

uses_free_run — whether THIS request would consume the org's one free run.

run_price_cents still quotes the dollar price, exactly as it does for a credit-covered run, so never infer funding from the price: uses_free_run is the discriminator. null means eligibility could not be determined (billing inactive, or the read failed) and never "not free" — when it is null, affordable and shortfall_cents are null too, which is unknown, not unaffordable.

It is false for depth: max. The free run covers a Standard run; a Max request is refused before the free run is ever considered, and allowed carries that refusal.

free_run — present only when the free run's entity cap would trim THIS request. A free run researches at most one interaction's worth of entities and drops the rest rather than refusing, so the block names entity_cap, requested, researched and dropped. The run response returns the same block and is authoritative: dropped here is computed from the seeds as sent, while the run narrows first (reuse_existing, additive_to).

New on GET /v1/me

free_run_available — is the org's one free run still unspent, so you can check trial eligibility before committing to anything. Same nullability rule: null is "could not determine", never "no free run".

2026-09-08 — breaking, before GA

Proposing a Blueprint change now names the Blueprint.

WasNow
POST /v1/blueprints/proposePOST /v1/blueprints/{blueprint_id}/propose

If you change nothing, this call returns 404. No alias is kept.

Get a blueprint_id from GET /v1/blueprints. The old path proposed against whichever Blueprint happened to be active — a choice you never made and the response never named. With two Blueprints in one account, it could return a completely coherent proposal about the wrong one.

This is not only a path change. The id now reaches everything the answer depends on: the Blueprint the proposal is built from, the Blueprint the tier is classified against, and the live tables checked to decide whether a change would lose data. A path that took an id and ignored it would have been worse than the old one, because the id would have implied a control it did not have.

Also in the response

blueprint_id — the Blueprint this proposal is about, echoed in the form GET /v1/blueprints uses. It is always present.

Name that Blueprint when you hand the change to a person. The {app_url}/blueprint?ask=… link opens their active Blueprint, which is not necessarily the one you addressed, and their chat re-derives the proposal from your text alone. If those differ, the re-derivation succeeds against the wrong Blueprint — no error. There is no flag to check instead: your active workspace comes from your API key, theirs from their own switcher, and nothing on this API reports the second.

Refusals

Addressing a Blueprint explicitly does not widen what you can reach. An id you could not already read refuses exactly as the other by-id reads do: 404 for unknown, malformed, or another organization's id (existence is never confirmed across organizations), 403 for a scoped viewer without a grant, and 409 for a Blueprint that is still a draft or has no tables yet. A refusal costs no model call.

Applying is unchanged and still human-only. An agent may ask what a change would be; only a person may make it.

Clients

Upgrade to at least:

ClientVersion
Python SDK (deepsieve)0.3.0
MCP server — the stdio package and browser login alike0.3.0

The MCP tool propose_blueprint_change takes an optional blueprint_id; omit it and it resolves the active Blueprint as before. The CLI does not call this endpoint and is unaffected.

2026-09-07 — breaking, before GA

A dataset read now names the Blueprint it reads. Two endpoints are removed and six are moved. This is a breaking change before GA, announced here as Versioning & stability requires: /v1 becomes additive-only at GA, and until then a break is allowed only when it is deliberate and appears in this changelog.

If you change nothing, the calls below return 404. That is an ordinary not-found, so a client that only checks for an error will look like it is reading an empty dataset rather than calling a route that no longer exists. Check the path before you check the data.

Removed

WasNow
GET /v1/dataGET /v1/blueprints/{blueprint_id}
GET /v1/data/{entity_key}GET /v1/blueprints/{blueprint_id}/entities/{entity_key}

Same response shape, same query parameters (limit, cursor, updated_since, fields, receipts), same free-preview cap. One field differs: the catalog's discriminator is now "object": "blueprint" rather than "object": "data_catalog".

Get a blueprint_id from GET /v1/blueprints, which lists the Blueprints you can see and marks the active one. That listing is the reason for the change. GET /v1/data answered for whichever Blueprint happened to be active — a choice the caller never made and the response never named — so an account with two Blueprints could receive a completely coherent answer to a question it had not asked, with nothing in the payload to reveal which one it described. No alias is kept: a shim with no consumer reads as a supported path.

GET /v1/export is unchanged, and still takes ?workspace_id=.

Moved

/v1/blueprints/onboarding/…/v1/blueprints/drafts/… — all six: the collection itself, {session_id}, and its /answers, /adjust, /chat and /approve. Path only. Same handlers, same request and response bodies, and the same operationIds, so generated SDK method names do not change.

Clients

Upgrade to at least:

ClientVersion
Python SDK (deepsieve)0.2.0
CLI (deepsieve)0.2.0
MCP server — the stdio package and browser login alike0.2.0

deepsieve data catalog and deepsieve data get resolve the active Blueprint for you, and take --blueprint <id> to name one instead. The MCP tools get_blueprint and query_entities take an optional blueprint_id, and a new list_blueprints tool supplies the ids — on both transports.

2026-08 (later)

  • ApiKey gains usage on GET /v1/keys{runs, est_spent_cents}, or null if the aggregation could not be completed. The API has returned it since the per-key usage work; the contract never declared it, so generated clients could not read it. Additive — existing fields unchanged. Scope worth knowing: it counts runs in your ACTIVE WORKSPACE. Keys are workspace-bound at mint time and the list is org-wide, so a key pinned to a different workspace reports zero rather than its real totals.

  • CreateRunRequest.reuse_existing was declared string; it is a boolean. A pasted property body had silently overwritten it in the contract, so SDK 0.1.1 types it Optional[str] and reuse_existing=True does not type-check. Corrected — the next SDK release carries the right type. Two other properties had the same defect without reaching the SDK: MonitoringView.freshness (object, was resolving to number) and StartRunResponse.reused_existing (carried the wrong description).

  • Freshness overage wording: the per-day rate and auto_topup_suggested described a report; both are metered per monitored run — one per Deep Research dossier, so a report assembled from several dossiers accrues several. Wording only; no behaviour or price changed.

  • CLI sign-inPOST /v1/auth/device/code and /v1/auth/device/token: the OAuth device flow behind deepsieve login. Unauthenticated by design; uses RFC 8628's own vocabulary (authorization_pending, slow_down, expired_token, access_denied), and the two retriable codes are the normal path, not failures.

  • New error codes: the four above. invalid_api_key is now returned for a credential that was presented but not accepted — previously indistinguishable from authentication_required, which means no credential was sent at all.

  • Citation gains verdict, verdict_note and cited. The API already returned them; the contract did not declare them, so generated clients could not read a verdict. Additive — existing fields unchanged. SDK 0.1.1 carries them.

  • MCP over browser login reaches tool parity with the stdio package (19 tools). No tool was removed.

2026-08

  • Initial /v1 release: typed error envelope + request ids; scoped revocable API keys (/v1/keys); async research runs with Idempotency-Key and query-first creation; outbound signed webhooks (run.*, dataset.updated); cursor-paginated dataset read (/v1/data) with updated_since sync and per-cell citations; NDJSON/JSON/CSV export; RateLimit headers + per-key budgets; MCP server; /llms.txt.
Changelog — DeepSieve API