View as markdown
Endpoints · Events

All events

GEThttps://api.tickerbot.io/v2/events

The unified cross-ticker event stream — "all splits this month", "every analyst action in my universe this week" — one call instead of one per ticker. The default stream is the four corporate kinds, each backed by its own archive: dividend, split, insider, analyst. Two more kinds join the timeline as explicit opt-ins (name them in kind to include them): signal — boolean-flag firings as enter/exit point-events — and news — headline events mirroring /v2/news. Rows are { ticker, ts, kind, payload }, newest first; payload fields per kind are identical to /v2/tickers/{ticker}/events (corporate kinds) and /v2/analyst/events (analyst — see Analyst actions), so consumers can switch scope without reshaping.

Those two routes remain as the single-ticker and analyst-specialized (firm/action filters) views of the same data.

The endpoint speaks the SQL grammar over a normalized projection of exactly four columns — ticker, ts, kind, and payload (jsonb). Optional q filters rows (kind='analyst' AND payload->>'action'='downgrades'); group_by (with optional select/having) switches to aggregate rollups (group_by=payload->>'firm' AS firm). Payload fields are reached with jsonb operators and cast as needed: (payload->>'shares')::numeric > 1e6. No other identifiers are accepted — this is the event log's own grammar, not the ticker-state scan grammar. Aggregates don't paginate: past limit you get truncated: true — narrow the window instead.

`join=state` (paid plans) widens the grammar to ticker-STATE columns, evaluated against each event's ticker as of the event's timestamp — point-in-time replay. "Downgrades on stocks above their 200-day" is one call: kind=analyst&join=state&q=payload->>'action'='downgrades' AND above_sma_200 = true. State resolves at daily resolution — the response's query echo carries join: "state" and state_resolution: "1d"; works in row and aggregate mode; gated Hobby and above (403 plan_required on Free).

Requires at least one bound — a ticker scope or a time window (q alone does not count); a bare kind over millions of rows is refused. kind=signal is filter-mode only: q, aggregates, and join=state over the signal log are refused with a 400 — scope with the filter params and filter client-side, or use signal spans / transitions_only. Both GET and POST are supported; POST takes the same parameters in the body for long queries. Pagination note: the cursor pages strictly *older* than the last row's timestamp, and the corporate archives are date-grained — same-date remainders can fall on a page boundary. Raise limit (max 1000) to avoid boundaries. A q too long to ride inside the cursor token sets q_truncated: true on the response — resend q alongside cursor on later pages.

string

Comma list of kinds to include. Omitted → the four corporate kinds; signal and news join only when named here.

string

Single-ticker filter. When both ticker and tickers are passed, ticker wins.

string

Comma list of tickers (max 50). Mutually exclusive with universe.

string

Universe slug (top_10, top_100, or one of yours) to scope the stream. Mutually exclusive with tickers.

string

Events at/after this ISO date or datetime.

string

Events strictly before this ISO date or datetime.

string

SQL WHERE over the projection — only ticker, ts, kind, payload may appear (plus ticker-state columns when join=state). Max 4000 chars. ANDs with the filter params. See the schema for columns + flags you can compose.

string

Set to state to allow ticker-state columns in q/select/group_by/having, evaluated as of each event's timestamp (daily resolution). Paid plans (Hobby and above).

string

Aggregate-mode output columns (requires group_by). Default: group keys + COUNT(*) AS events.

string

Comma list of rollup keys — switches the response to aggregate rows.

string

Post-aggregation filter. Requires group_by.

string

Aggregate-mode sort column or alias. Default: events. (Row mode is always newest-first.)

stringdefault desc

Aggregate-mode sort direction.

integerdefault 50

Page size (row modes) / max rollup rows (aggregate mode). Max 1000.

string

Opaque cursor from the previous response — carries the original filters (and q when short), so pass it alone. Not valid with group_by.

200
Envelope with query, count, next_cursor (plus q_truncated: true when an oversized q could not ride the cursor), and results of { ticker, ts, kind, payload } (row modes) or rollup rows plus truncated: true when the aggregate exceeds limit.
400
Bad kind, >50 tickers, tickers+universe together, no bound at all, kind=signal with q/group_by/join=state (filter mode only), invalid timestamps/cursor, or invalid_query — an identifier outside the projection (or outside the widened set under join=state), a disallowed function, select/having/order without group_by, or cursor with group_by.
403
plan_requiredjoin=state on the Free plan.
404
Referenced universe does not exist.
503
kind_unavailable — the signal event log is temporarily unavailable; retry later. The other kinds are unaffected.