/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
| Method | Path | Purpose |
|---|---|---|
GET | /api/thesis | List your theses. |
POST | /api/thesis/create | Create 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— returns202immediately 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 on200.
| Field | Type | Required | Notes |
|---|---|---|---|
rawThesis | string | yes | Testable claim, ≥ 20 characters. Examples: "Bitcoin closes 2026 above $50,000", "The Fed cuts rates at least once in Q2 2026". |
title | string | optional | Display title. Defaults to a derived short form of rawThesis. |
webhookUrl | string (https) | optional | Per-thesis webhook called when evaluations / status changes happen. |
metadata | object | optional | Free-form metadata stored on the thesis. Heartbeat writes its config under metadata.heartbeat. |
code: THESIS_NOT_A_CLAIM. Statements shorter than 20 chars return THESIS_TOO_SHORT.
Response (202 / 200)
?sync=true, tree is populated and status is active on success.
Errors
| Status | code / error | Cause |
|---|---|---|
400 | rawThesis is required | Missing field. |
400 | THESIS_TOO_SHORT | < 20 chars after trim. |
400 | THESIS_NOT_A_CLAIM | Classifier rejected as non-testable. |
401 | unauthorized | No / invalid auth. |
GET /api/thesis/
Returns the full state, including tree, positions, and strategies merged into one document.PATCH /api/thesis/
Body (all optional)| Field | Type | Notes |
|---|---|---|
title | string | Display title. |
webhookUrl | string | null | Set or clear the per-thesis webhook. |
status | "active" | "archived" | "watched" | Lifecycle. |
metadata | object | Replaces metadata at the top level. To preserve heartbeat config, read first then merge. |
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
| Field | Type | Required | Notes |
|---|---|---|---|
type | string | yes | One of news, price_move, user_note, external. |
content | string | yes | Free-form content — headline, observation, link. |
source | string | optional | Display source attribution (URL or name). |
400 type and content are required, 404 Thesis not found.
Evaluation
| Status | Body | Cause |
|---|---|---|
400 | Thesis is <status>, not active | Cannot evaluate archived or forming theses. |
404 | Thesis not found | Wrong owner / id. |
Augment
{ depth?: number, focusNodeId?: string } to scope the augmentation.
Response 200
| Status | Body | Cause |
|---|---|---|
400 | Thesis is <status>, not active | Cannot augment unless status: "active". |
404 | Thesis not found | Wrong owner / id. |
Causal-tree node mutation
| Field | Type | Required | Notes |
|---|---|---|---|
updates | array | yes | Each entry: { nodeId: string, probability: number /* 0-1 */, reason?: string }. |
lock | array of nodeIds | optional | Lock these nodes from automatic updates until manually unlocked. |
| Status | Body | Cause |
|---|---|---|
400 | updates array required | Missing or empty. |
400 | Each update needs nodeId and probability | Malformed entry. |
400 | probability must be 0-1, got X for nodeY | Out of range. |
400 | Thesis has no causal tree | Thesis still forming. |
404 | Node X not found in causal tree | Bad nodeId. |
Fork / evolve
- 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.
| Status | Body | Cause |
|---|---|---|
403 | Only the owner can evolve a thesis into a new frame | Evolve mode by non-owner. |
Context / read
| Method | Path | Purpose |
|---|---|---|
GET | /api/thesis/{id}/context | Tree + edges + positions in agent-shaped format. |
GET | /api/thesis/{id}/changes?since=... | Changes since timestamp. |
GET | /api/thesis/{id}/prompt | Generated agent prompt for this thesis. |
GET | /api/thesis/{id}/evaluations | Evaluation history (daily-aggregated confidence trajectory). |
Heartbeat
Positions
POST body — required
| Field | Type | Notes |
|---|---|---|
venue | "kalshi" | "polymarket" | Venue. |
externalMarketId | string | Kalshi ticker or Polymarket conditionId. |
marketTitle | string | Display title saved on the position. |
direction | "yes" | "no" | Contract side. |
entryPrice | number | Entry price in cents. |
POST body — optional
| Field | Type | Notes |
|---|---|---|
quantity | integer | Contract quantity. |
notes | string | Analyst notes. |
metadata | object | Free-form. |
{ id: <posId> } with status 201.
PATCH accepts any subset of those fields. DELETE records an exit timestamp; positions are not hard-deleted.
Strategies
POST and PATCH accept the same body shape; POST requires the core fields, PATCH only the fields you want to change.
Body fields
| Field | Type | Notes |
|---|---|---|
direction | "long" | "short" | Strategy direction. |
horizon | string | Time horizon ("1d", "1w", "1m", …). |
entryBelow | number | Enter long below this price (cents). |
entryAbove | number | Enter short above this price (cents). |
stopLoss | number | Stop in cents. |
takeProfit | number | Take-profit in cents. |
maxQuantity | integer | Max contracts across the strategy. |
perOrderQuantity | integer | Max contracts per order. |
softConditions | string[] | NL conditions evaluated by smart-mode runtime. |
rationale | string | Why-string. |
entry | object | Structured entry plan. |
exit | object | Structured exit plan. |
sizing | object | Sizing plan (Kelly, fixed, …). |
priority | integer | Higher priority strategies are evaluated first. |
status | "active" | "paused" | "archived" | Lifecycle. |
executedQuantity | integer | Read-mostly; tracked by the runtime. |
Publishing
POST body
| Field | Type | Required | Notes |
|---|---|---|---|
slug | string | yes | URL slug (lowercase, hyphens, 3–60 chars). |
description | string | optional | Short description shown on the public page. |
| Status | Body | Cause |
|---|---|---|
400 | slug is required | Missing slug. |
400 | <message> | Slug already in use, slug malformed, or thesis not in a publishable state. |
401 | unauthorized | No / 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
| Method | Path | Purpose |
|---|---|---|
GET | /api/public/theses | List 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. |
What-if
Body
| Field | Type | Notes |
|---|---|---|
overrides | object | { <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. |
| Status | Body | Cause |
|---|---|---|
400 | Thesis missing causal tree or edge analysis | Thesis hasn’t formed yet. |
404 | Thesis not found | Wrong owner / id. |
Video
| Method | Path | Notes |
|---|---|---|
GET | /api/thesis/{id}/videos | List linked videos. |
POST | /api/thesis/{id}/videos | Attach a video record. |
GET | /api/thesis/{id}/video-data | Render-ready data bundle for video generation. |
SDK and Agent SDK mapping
The TypeScript SDK exposes this thesis surface undersf.theses.*:
| SDK method | Route | |
|---|---|---|
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=true | false` |
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} |
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
| CLI | Endpoint |
|---|---|
sf list | GET /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 X | POST /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.