Skip to main content
Thesis owner endpoints live under /api/thesis/* and require authentication (Authorization: Bearer sf_live_... or browser session), except the public ticker lookup noted below. The CLI, TypeScript SDK, and Agent SDK call the same routes — see Thesis lifecycle for the conceptual model and Heartbeat for the per-thesis monitor loop. A private thesis is owned by exactly one user. Owner read and write paths 404 when the caller does not own the resource. Public thesis reads return only published thesis data.

CRUD

MethodPathPurpose
GET/api/thesisList your theses.
POST/api/thesis/createCreate a new thesis. Optional ?sync=true waits for formation.
GET/api/thesis/{id}Full detail — tree, metadata, positions, strategies.
PATCH/api/thesis/{id}Update title, webhookUrl, status, or metadata.
DELETE/api/thesis/{id}Delete the thesis and all related rows.
GET/api/thesis/by-ticker/{ticker}Public lookup for a published thesis referencing a market ticker, if any.

POST /api/thesis/create

Two modes:
  • POST /api/thesis/create — returns 202 immediately and forms the causal tree in the background.
  • POST /api/thesis/create?sync=true — runs formation inline (up to 5 minutes) and returns the formed thesis on 200.
Body
FieldTypeRequiredNotes
rawThesisstringyesTestable claim, ≥ 20 characters. Examples: "Bitcoin closes 2026 above $50,000", "The Fed cuts rates at least once in Q2 2026".
titlestringoptionalDisplay title. Defaults to a derived short form of rawThesis.
webhookUrlstring (https)optionalPer-thesis webhook called when evaluations / status changes happen.
metadataobjectoptionalFree-form metadata stored on the thesis. Heartbeat writes its config under metadata.heartbeat.
A claim classifier rejects rationale, action verbs, single tickers, or unverifiable statements with code: THESIS_NOT_A_CLAIM. Statements shorter than 20 chars return THESIS_TOO_SHORT. Response (202 / 200)
{
  "id": "thesis_01J0...",
  "status": "forming",
  "title": "Fed cuts in 2026",
  "tree": null,
  "createdAt": "2026-05-05T20:01:33.000Z"
}
With ?sync=true, tree is populated and status is active on success. Errors
Statuscode / errorCause
400rawThesis is requiredMissing field.
400THESIS_TOO_SHORT< 20 chars after trim.
400THESIS_NOT_A_CLAIMClassifier rejected as non-testable.
401unauthorizedNo / invalid auth.

GET /api/thesis/

Returns the full state, including tree, positions, and strategies merged into one document.
{
  "id": "thesis_01J0...",
  "title": "Fed cuts in 2026",
  "rawThesis": "...",
  "status": "active",
  "tree": { /* root node, children, edges */ },
  "metadata": { "heartbeat": { /* see /concepts/heartbeat */ } },
  "positions": [ /* see Positions section */ ],
  "strategies": [ /* see Strategies section */ ],
  "createdAt": "...",
  "updatedAt": "..."
}

PATCH /api/thesis/

Body (all optional)
FieldTypeNotes
titlestringDisplay title.
webhookUrlstring | nullSet or clear the per-thesis webhook.
status"active" | "archived" | "watched"Lifecycle.
metadataobjectReplaces metadata at the top level. To preserve heartbeat config, read first then merge.
Returns the updated thesis. 404 when the thesis is not yours.

DELETE /api/thesis/

Hard-deletes the thesis and all related rows (signals, evaluations, positions, strategies, notifications). Returns { ok: true } on success.

Signals

POST /api/thesis/{id}/signal
Inject evidence into a thesis. The monitor loop also writes signals automatically; this endpoint is for analyst notes, off-platform news, or programmatic forwards. Body
FieldTypeRequiredNotes
typestringyesOne of news, price_move, user_note, external.
contentstringyesFree-form content — headline, observation, link.
sourcestringoptionalDisplay source attribution (URL or name).
Response 200
{ "id": "sig_...", "thesisId": "thesis_...", "type": "news", "createdAt": "..." }
Errors: 400 type and content are required, 404 Thesis not found.

Evaluation

POST /api/thesis/{id}/evaluate
Triggers a deep evaluation cycle on demand. Heartbeat runs evaluations on its own cadence — only call this for an immediate refresh. Errors
StatusBodyCause
400Thesis is <status>, not activeCannot evaluate archived or forming theses.
404Thesis not foundWrong owner / id.
Response 200: full evaluation result — confidence, node probabilities, signals consumed, killConditions checked, model used, cost.

Augment

POST /api/thesis/{id}/augment
Runs LLM-driven causal-tree augmentation. The model proposes new nodes, edges, and probabilities based on the current state and recent signals. Body: none required. Optionally pass { depth?: number, focusNodeId?: string } to scope the augmentation. Response 200
{
  "thesisId": "thesis_01J0...",
  "addedNodes": 3,
  "updatedNodes": 5,
  "tree": { /* full updated causal tree */ },
  "modelUsed": "anthropic/claude-sonnet-4.6",
  "costUsd": 0.0042
}
Errors
StatusBodyCause
400Thesis is <status>, not activeCannot augment unless status: "active".
404Thesis not foundWrong owner / id.

Causal-tree node mutation

POST /api/thesis/{id}/nodes
Direct, zero-LLM-cost edits to the tree. Use this when an analyst overrides a probability or locks a node from automatic updates. Body
FieldTypeRequiredNotes
updatesarrayyesEach entry: { nodeId: string, probability: number /* 0-1 */, reason?: string }.
lockarray of nodeIdsoptionalLock these nodes from automatic updates until manually unlocked.
Errors
StatusBodyCause
400updates array requiredMissing or empty.
400Each update needs nodeId and probabilityMalformed entry.
400probability must be 0-1, got X for nodeYOut of range.
400Thesis has no causal treeThesis still forming.
404Node X not found in causal treeBad nodeId.

Fork / evolve

POST /api/thesis/{id}/fork
Two modes, both POST:
  • Pure fork: empty body or {} — clones the thesis as-is for a new owner-perspective.
  • Evolve: send { newRawThesis, newTitle?, reason?, inheritEdgeMarketIds? } — creates a new thesis as a frame-shift of the old one. Owner-only.
Errors
StatusBodyCause
403Only the owner can evolve a thesis into a new frameEvolve mode by non-owner.

Context / read

MethodPathPurpose
GET/api/thesis/{id}/contextTree + edges + positions in agent-shaped format.
GET/api/thesis/{id}/changes?since=...Changes since timestamp.
GET/api/thesis/{id}/promptGenerated agent prompt for this thesis.
GET/api/thesis/{id}/evaluationsEvaluation history (daily-aggregated confidence trajectory).

Heartbeat

GET   /api/thesis/{id}/heartbeat
PATCH /api/thesis/{id}/heartbeat
See Heartbeat for the full schema, validation ranges, defaults, and CLI mapping.

Positions

GET    /api/thesis/{id}/positions
POST   /api/thesis/{id}/positions
PATCH  /api/thesis/{id}/positions/{posId}
DELETE /api/thesis/{id}/positions/{posId}
Positions linked to a thesis. The runtime, autopilot, and CLI write to this surface; user-side code can also attach external positions for backtests or analyst notes.

POST body — required

FieldTypeNotes
venue"kalshi" | "polymarket"Venue.
externalMarketIdstringKalshi ticker or Polymarket conditionId.
marketTitlestringDisplay title saved on the position.
direction"yes" | "no"Contract side.
entryPricenumberEntry price in cents.

POST body — optional

FieldTypeNotes
quantityintegerContract quantity.
notesstringAnalyst notes.
metadataobjectFree-form.
Returns { id: <posId> } with status 201. PATCH accepts any subset of those fields. DELETE records an exit timestamp; positions are not hard-deleted.

Strategies

GET    /api/thesis/{id}/strategies        ?status=active
POST   /api/thesis/{id}/strategies
PATCH  /api/thesis/{id}/strategies/{sid}
DELETE /api/thesis/{id}/strategies/{sid}
A strategy is a structured plan for trading the thesis — direction, horizon, entry / stop / take-profit, sizing, soft conditions. Both POST and PATCH accept the same body shape; POST requires the core fields, PATCH only the fields you want to change.

Body fields

FieldTypeNotes
direction"long" | "short"Strategy direction.
horizonstringTime horizon ("1d", "1w", "1m", …).
entryBelownumberEnter long below this price (cents).
entryAbovenumberEnter short above this price (cents).
stopLossnumberStop in cents.
takeProfitnumberTake-profit in cents.
maxQuantityintegerMax contracts across the strategy.
perOrderQuantityintegerMax contracts per order.
softConditionsstring[]NL conditions evaluated by smart-mode runtime.
rationalestringWhy-string.
entryobjectStructured entry plan.
exitobjectStructured exit plan.
sizingobjectSizing plan (Kelly, fixed, …).
priorityintegerHigher priority strategies are evaluated first.
status"active" | "paused" | "archived"Lifecycle.
executedQuantityintegerRead-mostly; tracked by the runtime.

Publishing

POST   /api/thesis/{id}/publish
DELETE /api/thesis/{id}/publish

POST body

FieldTypeRequiredNotes
slugstringyesURL slug (lowercase, hyphens, 3–60 chars).
descriptionstringoptionalShort description shown on the public page.
Response 200
{ "published": true, "url": "/thesis/my-fed-cut-thesis" }
Errors
StatusBodyCause
400slug is requiredMissing slug.
400<message>Slug already in use, slug malformed, or thesis not in a publishable state.
401unauthorizedNo / invalid auth.

DELETE

Returns { "unpublished": true }. The public page returns 404 immediately; the underlying thesis is unaffected. Public theses are reachable at /thesis/{slug} for browsers and GET /api/public/thesis/{slug} for agents.

Public thesis reads

MethodPathPurpose
GET/api/public/thesesList published theses. Optional ?changes_only=true filters to theses with material recent changes.
GET/api/public/thesis/{slug}Public thesis detail by slug.
GET/api/thesis/by-ticker/{ticker}Public ticker-to-thesis lookup for published theses.
These public endpoints do not require browser session ownership. SDK and Agent SDK callers still use an API-keyed client by default because the strict SDK/Agent contract is API-key-first for hosted reads.

What-if

POST /api/thesis/{id}/whatif
Runs a counter-factual evaluation. The response shows projected confidence and edge metrics under the override scenario without writing an evaluation row.

Body

FieldTypeNotes
overridesobject{ <nodeId>: <probability 0-1>, ... } — values to apply on top of the current causal tree. Empty object is allowed; the result is the current state recomputed.
Errors
StatusBodyCause
400Thesis missing causal tree or edge analysisThesis hasn’t formed yet.
404Thesis not foundWrong owner / id.

Video

MethodPathNotes
GET/api/thesis/{id}/videosList linked videos.
POST/api/thesis/{id}/videosAttach a video record.
GET/api/thesis/{id}/video-dataRender-ready data bundle for video generation.

SDK and Agent SDK mapping

The TypeScript SDK exposes this thesis surface under sf.theses.*:
SDK methodRoute
sf.theses.list()GET /api/thesis
sf.theses.get(id)GET /api/thesis/{id}
sf.theses.update(id, body)PATCH /api/thesis/{id}
sf.theses.delete(id)DELETE /api/thesis/{id}
sf.theses.create(body)POST /api/thesis/create
sf.theses.signal(id, body)POST /api/thesis/{id}/signal
sf.theses.context(id)GET /api/thesis/{id}/context
sf.theses.changes(id, { since })GET /api/thesis/{id}/changes
sf.theses.heartbeat.get(id) / .update(id, body)GET / PATCH /api/thesis/{id}/heartbeat
sf.theses.nodes.update(id, body)POST /api/thesis/{id}/nodes
sf.theses.positions.*/api/thesis/{id}/positions
sf.theses.strategies.*/api/thesis/{id}/strategies
sf.theses.evaluations.list(id)GET /api/thesis/{id}/evaluations
sf.theses.whatIf(id, body)POST /api/thesis/{id}/whatif
sf.theses.evaluate(id)POST /api/thesis/{id}/evaluate
sf.theses.augment(id, { dryRun? })`POST /api/thesis//augment?dryRun=truefalse`
sf.theses.fork(id, body)POST /api/thesis/{id}/fork
sf.theses.publish(id, body) / .unpublish(id)POST / DELETE /api/thesis/{id}/publish
sf.theses.publicList()GET /api/public/theses
sf.theses.publicGet(slug)GET /api/public/thesis/{slug}
sf.theses.publicByTicker(ticker)GET /api/thesis/by-ticker/{ticker}
Agent SDK canonical tools mirror the same names with dotted tool ids, for example theses.context, theses.heartbeat.update, theses.positions.create, theses.strategies.list, theses.evaluate, and theses.public.get. Read tools have sideEffect: none; thesis mutation, evaluation, augmentation, fork, publish, and unpublish tools are sideEffect: user_write and require explicit Agent policy allowance.

CLI shorthand

CLIEndpoint
sf listGET /api/thesis
sf get <id>GET /api/thesis/{id}
sf create "<thesis text>"POST /api/thesis/create
sf signal <id> "<content>"POST /api/thesis/{id}/signal
sf evaluate <id>POST /api/thesis/{id}/evaluate
sf augment <id>POST /api/thesis/{id}/augment
sf heartbeat <id>GET / PATCH /api/thesis/{id}/heartbeat
sf publish <id> --slug XPOST /api/thesis/{id}/publish
sf unpublish <id>DELETE /api/thesis/{id}/publish
sf whatif <id>POST /api/thesis/{id}/whatif
sf delta <id>GET /api/thesis/{id}/changes

See also

Thesis lifecycle

Conceptual model and CLI walkthrough.

Heartbeat

Per-thesis monitor loop schema.

Direct API access

Auth, base URLs, and first calls.

Errors

Full error envelope reference.