Skip to main content
The WebSocket stream pushes the real-time event layer to you as it is written, so you never poll. Everything FocusAlpha reads — news wires, SEC filings, Asian exchange disclosures, company IR pages, earnings calls — lands in one append-only log, and your socket receives each row the moment it is inserted.

Two interfaces, one join key

Every row carries a stream field with one of two values. They are two different products: Merged is the compression for humans; raw is everything the compression was based on. A raw row’s triggered_revision says which merged revision it caused (or null if it changed nothing) — that is how you answer “what was this conclusion based on”. See Events interface and Raw news interface for the payloads, and Event labels for the taxonomy both speak.

Connect

1

Mint a stream token

The token lives one hour. Mint a new one before it expires and reconnect — your position is not stored in the token (see step 4), so rotation loses nothing.
2

Subscribe

The stream speaks the Supabase Realtime protocol, so the simplest client is @supabase/supabase-js — connect with the URL and token from the response:
Each row is { seq, stream, event_id, revision, payload, created_at } — the payload is the full message documented on the next two pages.
3

Filter client-side

The socket delivers both interfaces; keep the one you want:
Filtering by symbol, company or label family is also yours to do client-side — the payload’s own symbols, company_id and labels fields are the things to match on.
4

Catch up after a disconnect

Your whole position is one integer: the highest seq you have processed. On reconnect, fill the gap with the catch_up URL from the token response — the same token authorizes it:
Rows come back in seq order; process them, then resume the socket. A consumer that stores nothing but last_seq can always recover.

Delivery semantics

  • At-least-once. Dedupe merged rows on (event_id, revision) and raw rows on the payload’s id — both are stable across any re-delivery.
  • Rows are never edited. A changed conclusion is a new revision, never an update to an old row, so your copy can be append-only too.
  • seq is monotonic across the whole log; revision is monotonic per event. Gaps are detectable and repairable from your side (delta.since_revision on the Events interface tells you exactly which revision to backfill).
  • Freshness: the producer writes to the log on a ~2-minute cycle; the socket removes polling, not that cycle. End-to-end from a filing’s acceptance to a row on your socket is typically a few minutes.
The WebSocket has no server-side filtering — every subscriber sees every insert. If you want us to filter (by symbols, companies or label families) and POST to your endpoint instead, webhook subscriptions over the same log exist — POST /v1/events/subscriptions (Events) and POST /v1/news/subscriptions (Raw news) — with the same one-integer cursor and replay.

Plans

The event streams are Fund plan.