Fintech app
Tickerbot is the stock market, in SQL. A fintech app is four calls on it: the row, the series, the socket, and a watchlist per user.
A dashboard is rows, widgets, and freshness — three calls against one computed table: a row that already contains every signal, series that arrive pre-aligned, and a socket that pushes each recompute.
1. The row
One call returns everything a ticker card or table row could show: every one of the 421+ signals.
curl "https://api.tickerbot.io/v2/tickers/AAPL" \
-H "Authorization: Bearer YOUR_KEY"{
"as_of": "2026-08-21T13:00:18Z",
"ticker": "AAPL",
"data": {
"ticker": "AAPL",
"name": "Apple Inc.",
"price": 312.14,
"day_change_pct": 0.0027,
"rsi_14": 49.68,
"above_sma_200": true,
…
}
}2. The widgets
Whatever a widget renders — a chart, a sparkline, a gauge, a table of history — /v2/series feeds it: up to 50 tickers × 25 columns on one aligned time grid.
curl "https://api.tickerbot.io/v2/series?tickers=AAPL,MSFT,NVDA&columns=close,rsi_14,volume_today&interval=1d&from=2026-01-01" \
-H "Authorization: Bearer YOUR_KEY"{
"interval": "1d",
"tickers": ["AAPL", "MSFT", "NVDA"],
"columns": ["close", "rsi_14", "volume_today"],
"count": 477,
"series": {
"AAPL": [
{ "t": "2026-01-02", "close": 271.01, "rsi_14": 43.79, "volume_today": 37838054 },
…
{ "t": "2026-08-20", "close": 311.22, "rsi_14": 48.86, "volume_today": 25926977 }
],
"MSFT": [ … ], "NVDA": [ … ]
}
}3. The freshness
Hold a websocket open and each subscribed ticker's freshly-computed row arrives on every refresh cycle — the same record as GET /v2/tickers/{ticker}, pushed.
import WebSocket from 'ws'
const KEY = process.env.TICKERBOT_API_KEY
const rows = new Map() // ticker → latest computed row: the dashboard's state
const ws = new WebSocket('wss://api.tickerbot.io/v2/stream')
ws.on('open', () => ws.send(JSON.stringify({ type: 'auth', api_key: KEY })))
ws.on('message', (buf) => {
const frame = JSON.parse(buf.toString())
if (frame.type === 'authed') { // wait for the ack — subscribing in 'open' races auth
ws.send(JSON.stringify({ type: 'subscribe', tickers: ['AAPL', 'MSFT', 'NVDA'] }))
}
if (frame.type === 'update') { // { ticker, as_of, data }
rows.set(frame.ticker, frame.data) // full computed row — re-render from here
}
})4. Per-user watchlists
Model each user's watchlist as a universe and every surface scopes to it: the same list drives their table, their widgets, and their alerts.
curl -X POST "https://api.tickerbot.io/v2/universes" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "id": "watchlist_u123", "name": "u123 watchlist", "tickers": ["AAPL","NVDA"] }'{
"id": "watchlist_u123",
"name": "u123 watchlist",
"tickers": ["AAPL", "NVDA"],
"size": 2,
…
}The calls behind it
GET /v2/tickers/{ticker}— The card/row: every computed signal for one ticker, one responseGET /v2/series— The widgets: aligned multi-ticker, multi-column historyWS /v2/stream— The freshness: full recomputed rows pushed per refresh cyclePOST /v2/universes— Per-user watchlists: one list drives table, widgets, and alerts