| title | API Reference | ||||
|---|---|---|---|---|---|
| description | REST and WebSocket reference for the current get-rich-quick API server. | ||||
| status | canonical | ||||
| updated | 2026-04-08 | ||||
| tags |
|
Canonical route sources:
internal/api/server.gointernal/api/handlers.gointernal/api/auth.gointernal/api/websocket.gointernal/api/settings.go
REST API: http://localhost:8080/api/v1
WebSocket: ws://localhost:8080/ws
Ops: http://localhost:8080/healthz
http://localhost:8080/health
http://localhost:8080/metrics
GET /healthzGET /healthGET /metricsPOST /api/v1/auth/loginPOST /api/v1/auth/refreshPOST /api/v1/auth/register
Everything else under /api/v1/* requires one of:
Authorization: Bearer <access_token>or
X-API-Key: <api_key>- JWT access and refresh tokens are minted by
AuthManager. - API keys are supported through
X-API-Keyheader or?api_key=query param. - API keys are subject to a per-key token-bucket rate limiter.
- WebSocket upgrades require the same credentials:
Authorization: Bearer,X-API-Key,?token=, or?api_key=query params (for browsers that cannot send custom headers).
{
"error": "authentication required",
"code": "ERR_UNAUTHORIZED"
}{
"data": [],
"total": 42,
"limit": 50,
"offset": 0
}Notes:
limitdefaults to50limitis capped at100totalis populated for: strategies, runs, portfolio/positions, portfolio/positions/open, orders, trades, conversations, api-keys, runs/{id}/decisions, backtests/configs, backtests/runs, audit-log, events, discovery/resultstotalis omitted (0) for: memories (full-text search semantics differ), conversations/{id}/messages (synthetic message injection makes DB count inaccurate)
| Group | Routes |
|---|---|
| Auth | POST /auth/login, POST /auth/refresh, POST /auth/register |
| Account | GET /me, PATCH /me (password change) |
| API Keys | GET /api-keys, POST /api-keys, DELETE /api-keys/{id} |
| Strategies | GET/POST /strategies, GET/PUT/DELETE /strategies/{id}, lifecycle actions under /run, /pause, /resume, /skip-next |
| Runs | GET /runs, GET /runs/{id}, GET /runs/{id}/decisions, POST /runs/{id}/cancel, GET /runs/{id}/snapshot |
| Portfolio | GET /portfolio/positions, GET /portfolio/positions/open, GET /portfolio/summary |
| Orders | GET /orders, GET /orders/{id} |
| Trades | GET /trades |
| Memories | GET /memories, POST /memories/search, DELETE /memories/{id} |
| Risk | GET /risk/status, POST /risk/killswitch |
| Settings | GET /settings, PUT /settings |
| Events | GET /events |
| Conversations | GET/POST /conversations, GET/POST /conversations/{id}/messages |
| Audit log | GET /audit-log |
| Backtests | GET/POST /backtests/configs, GET/PUT/DELETE /backtests/configs/{id}, POST /backtests/configs/{id}/run, GET /backtests/runs, GET /backtests/runs/{id} |
| Discovery | POST /discovery/run, GET /discovery/results |
| Universe | GET /universe, GET /universe/watchlist, POST /universe/refresh, POST /universe/scan |
| Options | GET /options/chain/{underlying} |
| Calendar | GET /calendar/earnings, GET /calendar/economic, GET /calendar/ipo, GET /calendar/filings, POST /calendar/filings/analyze |
| Automation | GET /automation/status, GET /automation/health, POST /automation/jobs/{name}/run, POST /automation/jobs/{name}/enable |
| News | GET /news |
| Signals | GET /signals/evaluated, GET /signals/triggers, GET/POST /signals/watchlist, DELETE /signals/watchlist/{term} |
Backend root / is not documented here because the current Compose and production stack do not serve the frontend SPA from the API process. Public ops endpoints remain GET /healthz, GET /health, and GET /metrics.
- auth: public
- body:
username,password - behavior: loads the user by username, verifies bcrypt password, and returns access plus refresh tokens
Example:
{
"username": "demo",
"password": "demo-pass"
}Response:
{
"access_token": "eyJhbGciOiJI...",
"refresh_token": "eyJhbGciOiJI...",
"expires_at": "2026-04-03T18:40:00Z"
}- auth: public
- body:
refresh_token - behavior: validates the refresh token and returns a new pair
- auth: public
- body:
username,password - behavior: creates a new user and returns a token pair; returns
409 Conflictfor duplicate usernames
- auth: required
- returns the current user's profile (
id,username,created_at,updated_at)
- auth: required
- body:
current_password,new_password(minimum 8 characters) - behavior: verifies the current password, then replaces the bcrypt hash; returns
204 No Content
- auth: required
- returns a paginated list of API key metadata (raw key value is never re-exposed)
- includes revoked keys; check
revoked_atto filter active keys
- auth: required
- body:
name(required),expires_at(optional ISO 8601 timestamp) - returns the plaintext key once in
keyalongsidemetadata; store it securely — it cannot be retrieved again
- auth: required
- marks the key as revoked; returns
204 No Content - revocation is immediate: any in-flight request using the key will be rejected on next evaluation
- auth: required
- filters:
tickermarket_type(stock,crypto,polymarket,options) — invalid value returns400status(active,paused,inactive) — invalid value returns400is_paper(true/false)limit/offset
- response includes
total(total matching rows, regardless of pagination)
- auth: required
- body:
domain.Strategy - validation:
- required
name - required
ticker - valid
market_type - valid
status - valid typed JSON config if
configis present - valid standard cron expression in
schedule_cronif present — invalid expression returns400
- required
- auth: required
- returns one strategy
- auth: required
- full update semantics on the strategy record
- auth: required
- deletes the strategy record
- auth: required
- behavior:
- loads the strategy
- invokes the configured
StrategyRunner - persists and returns the run result
- broadcasts run, signal, order, and position events over the hub
- auth: required
- behavior: updates strategy status to
paused
- auth: required
- behavior: updates strategy status back to
active
- auth: required
- behavior: toggles skip-next-run state for scheduled execution
- auth: required
- filters:
strategy_id(UUID)tickerstatus(running,completed,failed,cancelled) — invalid value returns400trade_date(RFC3339 timestamp) — filters to runs for that specific trade datestart_date/end_date(RFC3339 timestamp, filter onstarted_at)limit/offset
- response includes
total(total matching rows, regardless of pagination)
- auth: required
- returns the pipeline run summary record
- auth: required
- filters:
limit,offset - enum filters:
agent_role(e.g.trader,market_analyst),phase(analysis,research_debate,trading,risk_debate) — invalid value returns400 - query:
include_prompt=trueto include full prompt text in each decision - returns
totalin list envelope - returns agent decisions associated with the run
- auth: required
- cancellation surface for in-flight runs where supported
- auth: required
- returns persisted run snapshot data for richer inspection/replay
- auth: required
- filters:
ticker,limit/offset - enum filters:
side(long,short) — invalid value returns400 - response includes
total
- auth: required
- filters:
ticker,limit/offset - enum filters:
side(long,short) — invalid value returns400 - returns only positions where
closed_atis null
- auth: required
- returns
open_positions(count),unrealized_pnl,realized_pnl
- auth: required
- filters:
ticker,broker,limit/offset - enum filters:
status(submitted,partial,filled,cancelled,rejected),side(buy,sell),order_type(market,limit,stop,stop_limit,trailing_stop) — invalid values return400 Bad Request - response includes
total
- auth: required
- returns the order record plus its fills (trades) in
fills
- auth: required
- filters:
order_id,position_id,ticker,side,start_date,end_date,limit/offset order_idandposition_idare mutually exclusive- response includes
total
- auth: required
- filters:
agent_role,q(search query),limit/offset
- auth: required
- body:
{"query": "your natural language query"} - returns memories ordered by relevance
- auth: required
- returns
204 No Content
- auth: required
- returns:
- high-level risk status
- circuit-breaker state
- kill-switch state
- position/exposure limits
- utilization figures
- auth: required
- toggles kill switch state
- body typically includes:
{
"active": true,
"reason": "operator action"
}- auth: required
- returns:
- LLM default provider and tier model selection
- provider configuration state with masked API-key info
- risk threshold settings
- system environment/version/uptime
- configured broker summary
- auth: required
- updates non-secret settings (model selections, provider base URLs, risk thresholds)
- changes are persisted to the
app_settingsDB table and survive restarts - API keys are never stored; they live only in the in-memory session until overwritten
- auth: required
- filters:
event_kind,pipeline_run_id,strategy_id,agent_role,after,before(RFC3339),limit/offset
- auth: required
- filters:
pipeline_run_id(UUID),limit/offset - enum filters:
agent_role(e.g.trader,market_analyst) — invalid value returns400 - returns
totalin list envelope
- auth: required
- body:
{"pipeline_run_id": "<uuid>", "agent_role": "<role>"} - auto-generates a title from the agent role and run ticker
- auth: required
- filters:
limit,offset - at
offset=0prepends agent pipeline decisions as synthetic assistant messages
- auth: required
- body:
{"role": "user", "content": "..."} - appends a message; assistant replies are generated via the configured LLM provider
- auth: required
- lists audit log entries for critical operator actions
- filters:
event_type— e.g.kill_switch.activated,strategy.manual_run,api_key.createdentity_type— e.g.system,strategy,api_key,user,marketactor— username who performed the actionentity_id— UUID of the specific entity affectedafter/before— ISO 8601 timestamp bounds oncreated_atlimit/offset
- response includes
total(total matching entries)
Audited event types:
| Event type | Trigger |
|---|---|
kill_switch.activated / .deactivated |
POST /risk/killswitch |
market_kill_switch.activated / .deactivated |
POST /risk/markets/{type}/stop|resume |
settings.updated |
PUT /settings |
strategy.manual_run |
POST /strategies/{id}/run |
strategy.paused / .resumed |
POST /strategies/{id}/pause|resume |
strategy.skip_next |
POST /strategies/{id}/skip-next |
user.registered |
POST /auth/register |
api_key.created / .revoked |
POST/DELETE /api-keys |
Example entry:
{
"id": "a1b2c3d4-...",
"event_type": "kill_switch.activated",
"entity_type": "system",
"actor": "admin",
"details": {"reason": "market volatility spike"},
"created_at": "2026-04-08T14:23:00Z"
}Backtests run the rules-engine pipeline over historical OHLCV bars. They require a strategy with a rules_engine key in its config.
- auth: required
- filters:
strategy_id(UUID),limit/offset - response includes
total
- auth: required
- body:
domain.BacktestConfig - required fields:
strategy_id,start_date,end_date,simulation.initial_capital
- auth: required
- returns one backtest config
- auth: required
- full update semantics
- auth: required
- returns
204 No Content
- auth: required
- runs the backtest synchronously and persists the result
- requires the target strategy to have a
rules_enginekey in its config JSON - fetches ~400 days of warmup bars before
start_datefor indicator initialization (SMA-200 etc.) - if the strategy status is
inactiveand the backtest yields a positive Sharpe ratio with at least one trade, the strategy is automatically promoted toactive - body: none
- returns a
BacktestRunrecord withmetrics,trade_log, andequity_curveas JSON blobs
- auth: required
- filters:
backtest_config_id(UUID),limit/offset - response includes
total
- auth: required
- returns one backtest run record
The automation subsystem runs named background jobs on a schedule. Requires ENABLE_SCHEDULER=true.
- auth: required
- returns a map of job name → status for all registered jobs
- returns
503 Service Unavailablewhen automation is not configured
- auth: required
- triggers the named job immediately, independent of its schedule
{name}must match a registered job (e.g.ticker_discovery,stocktwits_trending)- returns
400 Bad Requestwith an error message if the name is unknown
- auth: required
- body:
{"enabled": true}or{"enabled": false} - enables or disables the named job's scheduled execution
- returns
400 Bad Requestif the name is unknown
- auth: required
- returns structured health summary for all registered automation jobs
- response shape:
{ "healthy": true, "total_jobs": 3, "failing_jobs": 0, "jobs": [ { "name": "ticker_discovery", "enabled": true, "running": false, "last_run": "2026-04-11T12:00:00Z", "last_error": "", "error_count": 0, "consecutive_failures": 0, "run_count": 42 } ] } healthyisfalsewhen any job hasconsecutive_failures >= 3- returns
503 Service Unavailablewhen automation is not configured
Requires newsFeedRepo to be wired at startup (depends on FINNHUB_API_KEY or a news provider).
- auth: required
- filters:
ticker— when present, returns news scoped to that ticker; otherwise returns recent cross-market newslimit(default50)
- returns
503 Service Unavailablewhen the news feed is not configured
Real-time signal and trigger events from the signal intelligence subsystem. All endpoints return empty results (not errors) when the signal hub is not running.
- auth: required
- filters:
min_urgency(integer, 0–10),limit(default 50),offset - returns
StoredSignalrecords from the in-memory signal store - response shape:
{"data": [...], "total": N}
- auth: required
- filters:
limit(default 50),offset - returns trigger log entries from the in-memory store
- response shape:
{"data": [...], "total": N}
- auth: required
- returns all active watch terms (ticker symbols, keywords, strategy-scoped terms)
- response shape:
{"data": [...]}
- auth: required
- body:
{"term": "AAPL", "strategy_id": "<uuid>"}(strategy_idoptional) - adds a manual watch term to the signal index
- returns
201 Createdwith{"term": "..."}
- auth: required
- removes a manual watch term
- returns
204 No Content
All calendar endpoints require a configured eventsProvider (Finnhub is the primary source). Returns 501 Not Implemented otherwise.
Date parameters use YYYY-MM-DD format. Earnings and IPO endpoints default to now → now+7days when dates are omitted.
- auth: required
- filters:
from,to(YYYY-MM-DD) - returns upcoming earnings releases for all tracked tickers
- auth: required
- returns the upcoming economic event calendar (no date filter — provider returns its own window)
- auth: required
- filters:
from,to(YYYY-MM-DD) - returns expected IPO filings in the date window
- auth: required
- filters:
ticker,form(e.g.10-K,8-K),from,to(YYYY-MM-DD; defaults to last 30 days) - returns SEC filings matching the filter
- auth: required
- requires LLM provider configured; returns
501 Not Implementedotherwise - body:
{ "symbol": "AAPL", "form": "10-K", "url": "https://..." }symbol(string, required) — ticker symbolform(string, required) — SEC form type (e.g.10-K,8-K)url(string, required) — direct URL to the filing document
- returns an LLM-generated analysis of the filing (sentiment, key risks, summary)
Requires POLYGON_API_KEY and TICKER_DISCOVERY=true for automatic refresh. The universe repo and universe engine are wired independently — some endpoints may be unavailable when only one is configured.
- auth: required
- filters:
index_group(e.g.sp500,nasdaq100),search(prefix match),limit/offset
- auth: required
- query:
top(integer, default 30) — returns the top-N scored tickers - requires the
Universeengine (not just the repo)
- auth: required
- triggers a full constituent refresh from Polygon
- returns
503when universe engine not configured
- auth: required
- runs an immediate scoring pass over current constituents
Strategy discovery runs a screener → generator → sweep pipeline to identify and deploy new strategies. Requires POLYGON_API_KEY and LLM provider.
- auth: required
- triggers a synchronous discovery run
- runs screener (volume, momentum, volatility filters), LLM-based strategy generation, and parameter sweep
- returns
503when discovery deps not configured
- auth: required
- lists past discovery runs with candidate counts and deployment outcomes
- filters:
limit/offset - returns
totalin list envelope - returns
503when discovery run repo not configured
Endpoint:
GET /ws
The server accepts JSON messages shaped like:
{
"action": "subscribe",
"strategy_ids": ["..."],
"run_ids": ["..."]
}Supported actions:
subscribeunsubscribesubscribe_allunsubscribe_all
Acknowledgement format:
{
"status": "ok",
"action": "subscribe"
}Error format:
{
"type": "error",
"error": "invalid command JSON"
}strategy_idssubscribes to events for one or more strategiesrun_idssubscribes to a specific pipeline runsubscribe_allturns on broadcast delivery for all events
The server broadcasts event envelopes for things such as:
- pipeline start
- signal emission
- order submitted
- position update
The frontend run-detail page subscribes by run_id while a run is active.
PATCH /api/v1/meonly supports password change. There is no username change endpoint.- API key rate-limit-per-minute is set at creation time using the server default; it cannot be changed after creation without direct DB access.
- Backtest
schedule_cronfields are executed by the built-in cron engine only when the scheduler is initialized withWithBacktestScheduling().