REST & WebSocket API

The local Forven HTTP and WebSocket API — base URL, authentication keys, the endpoint catalog by router, the live feed, and the legacy sunset.

Forven runs a local FastAPI server. The desktop UI talks to it over HTTP on 127.0.0.1, and the same API is available to you for scripting, integrations, and diagnostics. This page is the developer reference: the base URL, how authentication works, the endpoint catalog grouped by router, the /ws/live WebSocket feed, and the deprecated routes scheduled for removal.

This is a local-first API. By default it binds to loopback only, the keys live on your machine, and nothing is exposed to the internet. If you only use the desktop app you never touch this directly — but everything the app does, you can do over HTTP.

Forven is a research tool. The trading, risk, and metrics endpoints described here drive a validation process, not a profit engine. Any numbers they return are illustrative of process, not predictions or recommendations, and nothing here is financial advice. Read going live safely before routing real capital.

Base URL

The server listens on http://127.0.0.1:8003 by default. Two settings change that, both via environment variables:

  • FORVEN_PORT — the listen port (default 8003). A startup guard detects port collisions.
  • FORVEN_BIND_HOST — the bind address (default 127.0.0.1, loopback only). Set this for LAN or dev access.

A DNS-rebinding guard rejects unexpected Host headers; the allowed set (FORVEN_ALLOWED_HOSTS) defaults to 127.0.0.1, localhost, [::1], and testserver. Browser calls are constrained by CORS — FORVEN_CORS_ORIGINS defaults to the local SvelteKit dev origins (http://127.0.0.1:5173, http://localhost:5173).

Almost every route is mounted under the /api prefix. The WebSocket feed and the /verdict/* routes are the notable exceptions.

Authentication

Forven has two keys with different privilege levels. Both are read from request headers and configured through environment variables.

KeyHeaderGrants
FORVEN_API_KEYx-api-key or Authorization: Bearer <key>Baseline access. Enforced globally by ApiKeyMiddleware on every request.
FORVEN_OPERATOR_KEYx-operator-keyOperator access. Required by most routers — agents, trading, paper, backtesting, approvals, brain, gauntlet, and more.

How the two layers stack

  1. ApiKeyMiddleware runs before route dispatch and checks FORVEN_API_KEY on all requests except /api/health, /api/webhooks/*, /api/shutdown, and OPTIONS. A mismatch returns 401 as a plain JSON response.
  2. require_operator_access is a FastAPI dependency applied at the router level on operator-gated routers. It validates FORVEN_OPERATOR_KEY and returns 401 if the key is missing or invalid, 503 if no operator key is configured at all.

In the endpoint catalog below, "operator-gated" means the whole router carries require_operator_access — every route in it needs the operator key.

Enforcement and the dev default

If FORVEN_API_KEY is unset, the API runs unauthenticated and logs a warning. That is acceptable for a loopback-only dev session; it is not acceptable for anything exposed.

Set FORVEN_AUTH_REQUIRED=true to make this a hard guarantee. When it is true, the server refuses to start unless both FORVEN_API_KEY and FORVEN_OPERATOR_KEY are set. Packaged builds use this to enforce authentication; the default is false for local development.

# Authenticated request to a baseline endpoint
$h = @{ "x-api-key" = $env:FORVEN_API_KEY }
Invoke-RestMethod -Uri "http://127.0.0.1:8003/api/health" -Headers $h

# Operator-gated endpoint needs both keys
$h = @{
  "x-api-key"      = $env:FORVEN_API_KEY
  "x-operator-key" = $env:FORVEN_OPERATOR_KEY
}
Invoke-RestMethod -Uri "http://127.0.0.1:8003/api/strategies" -Headers $h

Routes that skip auth by design

A handful of routes are intentionally auth-exempt:

  • GET /api/health — liveness check, no auth.
  • POST /api/shutdown — graceful shutdown, 127.0.0.1/::1 only, used by the Tauri shell to stop uvicorn. Returns 202.
  • /api/webhooks/* — exempt from key auth but HMAC-checked; dev-only (disabled in packaged builds).
  • The diagnostics, health-status, skills, deepdive, and sandbox-scan reads are exposed without operator gating as a frontend contract — see the catalog notes.

Endpoint catalog

The API surface is large — well over a hundred routes across more than two dozen routers. Rather than list every one, the tables below group them by router with representative endpoints. The pattern within a router is consistent: GET to read, POST/PUT/PATCH to mutate, DELETE to remove.

System, status & control plane

MethodPathPurpose
GET/api/healthLiveness check (no auth).
GET/api/system/statusSystem status summary.
GET/api/system/heartbeatDaemon heartbeat with risk/equity data.
GET/api/dashboardDashboard overview.
POST/api/system/stop · /api/system/startHalt or resume trading and agents (system pause).
GET POST/api/system/modeGet or set the pipeline autonomy mode (manual/semi_auto/auto).
POST/api/execution-modeSet the execution mode (paper/live); refused in beta builds.
POST/api/system/exchange/reconcileReconcile positions and orders with the exchange.
GET PATCH/api/scheduler · /api/scheduler/{job_id}List scheduler jobs and patch job config.

See Operations for the UI over these, and the scheduler page for the job catalog.

Strategies & lifecycle

The real pipeline stages are quick_screen → research_only → paper → live. (The marketing site calls the paper stage a "candidate"; the API uses paper.) Transitions respect a forward-only DAG — you cannot move a strategy backward from paper to research_only.

MethodPathPurpose
GET/api/strategiesList strategies by status/stage; paged; served via ORJSONResponse for large payloads.
GET/api/lifecycle/strategiesList by lifecycle state with state/source/symbol/name filters.
GET/api/lifecycle/strategies/{id}Lifecycle state plus full history.
POST/api/lifecycle/transitionMove a strategy between stages (target paper/live).
GET/api/lifecycle/strategies/{id}/readinessThe promotion-readiness checklist.

See the pipeline for what each stage means and promotion gates for the checks between them.

Backtesting, gauntlet & verdict

MethodPathPurpose
POST/api/backtesting/strategiesCreate a backtest strategy container (requires hypothesis_id).
GET/api/backtesting/datasetsList OHLCV datasets (filter by symbol/timeframe).
POST/api/gauntlet/strategies/{id}/workflowCreate or fetch the gauntlet workflow for a strategy.
GET/api/gauntlet/workflows/{id}Workflow detail with per-step status.
POST/api/gauntlet/workflows/{id}/resume · /cancelResume (with max_steps) or cancel a workflow.
POST/api/gauntlet/steps/{id}/retryRetry a single robustness step.
POST/verdict/runRun verdict validation on a backtest result.
GET/verdict/guideTest descriptions and thresholds.

The verdict engine runs the same robustness battery as the gauntlet: sample_size, statistical_significance, walk_forward, monte_carlo, param_jitter, cost_stress, and regime_split. Stale workflows are recovered at startup (a step is considered stale after one minute of no progress).

Trading & emergency controls

MethodPathPurpose
GET/api/trades/openOpen trades, optionally re-verified against the exchange.
GET/api/trades/recent · /api/tradesRecent trades and the full ledger (paged by status).
POST/api/trades/{id}/force-closeForce-close a position. Returns 502 if the close fails on the exchange.
POST/api/trades/{id}/mark-failedRecord a trade as failed and free its capital.
GET/api/strategies/{id}/live-signals · /live-indicators · /live-markersLive chart series and entry/exit markers.

force-close returns 502 Bad Gateway (not 400) on failure specifically to signal that the position may still be open on the exchange. Always re-check with GET /api/trades afterward. If you are unsure, mark-failed is the safer call. Live routing targets HyperLiquid, and beta builds hard-lock to paper.

Paper trading

MethodPathPurpose
GET/api/paper/sessionsList paper sessions (optional deployed filter).
POST/api/paper/service/start · /stopStart or stop the paper trading service.
GET/api/paper/sessions/{id}/tradesTrades for a session.

The paper service is global, not per-strategy — starting it stops any prior session. Paper sessions never auto-promote to live; you advance them through /api/lifecycle/transition. See paper trading.

Agents, model policy & approvals

MethodPathPurpose
GET/api/agents · /api/agents/{id}List agents and read agent detail.
PATCH DELETE/api/agents/{id}Update an agent's model/description, or delete it.
GET PUT/api/model-policyRead or update the global model-routing policy.
GET/api/agents/model-optionsAvailable models per provider (refresh=true re-fetches).
GET/api/agents/{id}/toolsets · PUT /api/agents/{id}/toolsets/{context}Read all per-context overrides; replace overrides for one context (scheduled/interactive/recovery/research).
GET/api/approvalsList approvals (filter by status/type/target/owner).
POST/api/approvals/{id}/approve · /deny · /revise · /classifyAct on an approval, or re-run the smart-approval classifier.
GET/api/approvals/modesApproval modes (manual/smart/off), deadlines, escalation owner.

Agents never place trades or task each other directly. See agents and the approval queue; model routing is covered under models & providers.

Brain, routines & memory

MethodPathPurpose
GET/api/brain/overview · /api/brain/memoryBrain state, activity, attention, and persistent memory.
POST/api/brain/chatQueue a brain prompt — returns 202 with a task_id.
POST/api/brain/chat/directRun a brain prompt synchronously (not queued).
GET POST/api/routinesList or create cron-scheduled routines.
POST/api/routines/{id}/runDispatch a routine immediately.
GET/api/skills · /api/skills/declining · /api/skills/{name}Quant-skills catalog, declining skills, skill detail.

Operator-created routines run without an approval; brain-authored routines go through the approval queue. See the brain, scheduled routines, and the memory bank.

MCP servers & tool grants

MethodPathPurpose
GET POST/api/mcp/serversList or register MCP servers (stdio/http, with tools_include/exclude).
GET PUT DELETE/api/mcp/servers/{name}Read, update, or unregister a server (cascades grant deletes).
GET/api/mcp/servers/{name}/toolsLive tool discovery (no registration side effect).
GET POST DELETE/api/mcp/agents/{id}/grantsManage per-agent server access.

The full setup is covered on the MCP server page.

Bot factory

MethodPathPurpose
GET POST/api/bot-factory/botsList or create autonomous trading bots.
PUT DELETE/api/bot-factory/bots/{id}Update or delete a bot.
POST/api/bot-factory/bots/{id}/start · /stopStart or stop a bot.
GET/api/bot-factory/bots/{id}/trades · /positionsBot trades and positions.
GET/api/bot-factory/templatesAvailable bot templates.

Bots marked running are re-spawned at startup, with a monitor thread handling heartbeat and restart. See the bot factory.

Hypotheses

MethodPathPurpose
GET/api/hypothesesList hypotheses (filter by view/lane/status/search).
POST/api/hypotheses/manual · /api/hypotheses/from_urlCreate a hypothesis manually or from a URL (preview first with /api/hypotheses/preview_url).
GET/api/hypotheses/{id}Read a hypothesis.
POST/api/hypotheses/{id}/updateEdit a hypothesis (title/thesis/mechanism/novelty).
POST/api/hypotheses/{id}/generate-strategiesSpawn child strategies from a thesis.

Spawn limits (per-run and rolling-window) prevent exhaustion — POST /api/backtesting/strategies returns 422 when a limit is hit. See hypothesis-driven research.

Data, notifications & diagnostics

MethodPathPurpose
POST/api/fetchFetch OHLCV data from an exchange.
GET/api/backtesting/datasetsDataset catalog.
GET/api/notificationsList notifications (filter by status/severity/source/type).
POST/api/notifications/{id}/acknowledge · /acknowledge-allAcknowledge one or all.
GET/api/diagnostics/snapshotHealth snapshot: cost rollups, truncation summary, health checks (frontend contract, no auth).
GET/api/diagnostics/resumableInterrupted tasks awaiting resume (no auth).
POST/api/diagnostics/resumable/{id}/resumeResume an interrupted task.
GET/api/health/status · /api/health/alertsComponent health and recent alerts (no auth).

See managing market data, notifications, and health monitoring.

Settings, profile & sandbox

MethodPathPurpose
GET/api/settings · PUT /api/settings/{section}Read all settings; update a section.
GET POST DELETE/api/settings/api-keysManage stored exchange/data-source credentials.
GET PUT/api/profileOperator profile (name, timezone, risk-per-trade, rules, prefs).
POST/api/sandbox/scanAST-only static analysis of strategy code (always available, no auth).
POST/api/sandbox/test · /api/sandbox/runs/{id}/killSubprocess smoke test and kill — return 503 unless the sandbox is enabled.
POST/api/deepdive/threads/{id}/sendStreaming SSE chat for a strategy.

The sandbox is disabled by default; only /scan (pure AST, no execution) is always available. Everything that spawns a subprocess returns 503 until you enable it under Settings → Sandbox. The deepdive chat is server-sent events, not WebSocket; see deep-dive strategy chat.

WebSocket live feed

The live feed streams price ticks, order fills, indicator updates, and regime changes to connected clients. There are two equivalent routes:

  • ws://127.0.0.1:8003/api/ws/live — the primary endpoint.
  • ws://127.0.0.1:8003/ws/live — an alias for the same handler.

Both are backed by the same websocket_endpoint. Use the feed to drive live charts and dashboard widgets instead of polling the trade endpoints.

# Quick check that the WebSocket route is reachable (requires the wscat npm package)
wscat --connect "ws://127.0.0.1:8003/ws/live"

Response and error conventions

A few behaviours are worth knowing before you script against the API:

  • 202 Accepted means queued work. POST /api/brain/chat returns a task_id; poll GET /api/brain/chat/{task_id}, which keeps returning 202 while the task runs.
  • 502 from force-close signals a possible still-open position — re-verify, never assume.
  • 503 means a capability is disabled (sandbox) or unconfigured (operator key) rather than broken.
  • 422 from strategy creation usually means a hypothesis spawn limit was reached.
  • The strategies router serializes with ORJSONResponse for large payloads; the response shape is plain JSON either way.
  • A rate limiter (SlowAPI) is installed when available; if it cannot load, it fails open as a no-op.

Legacy API & sunset

Older integrations used /api/forven/* paths. A compatibility middleware rewrites every /api/forven/* request to /api/* before routing, so the legacy paths still work today but are marked deprecated. They are scheduled for removal on June 30, 2026.

Migrate by dropping the forven segment: /api/forven/strategies becomes /api/strategies. No other change is required.

Caveats

  • Operator key is the real gate. Most useful routes are operator-gated; a baseline FORVEN_API_KEY alone will hit 401/503 on them.
  • Unauthenticated by default in dev. With no key set the API is open. Set FORVEN_AUTH_REQUIRED=true (and both keys) before binding to anything other than loopback.
  • Loopback-bound by design. Changing FORVEN_BIND_HOST widens exposure; pair it with authentication.
  • Some reads are intentionally ungated (diagnostics, health, skills, sandbox scan) as a frontend contract — do not treat their availability as a sign that all routes are open.
  • The simulation and Regime Lab routers are optional and return 404 unless explicitly enabled.

Forven is a research tool. The endpoints here surface a disciplined validation process; results are not predictive and nothing here is financial advice.