Get started

Quickstart

In five minutes: create a key, open a connection, subscribe to large aggressive orders on the E-mini Nasdaq-100 future (NQ), then ask for the same thing over a past period.

1. Create an API key

Sign in with your email address: you get a sign-in link, no password needed, and your account is created the first time you sign in. Then create a key in your account. Copy it right away: it is shown only once.

There are two kinds of keys:

  • test key (fc_test_…): free, data delayed by 10 minutes. Ideal for development;
  • live key (fc_live_…): gets the rights of your plans, including real-time data with the Live plan. Without a plan, it has the same rights as a test key; with the Live plan alone, it has no access to history.

Store the key in an environment variable on your server. In a macOS or Linux terminal (bash, zsh):

BASH
export FATHOM_CHARTS_API_KEY="fc_test_…"

On Windows, in PowerShell:

POWERSHELL
$env:FATHOM_CHARTS_API_KEY = "fc_test_…"

Or in the Command Prompt (cmd), without quotes:

CMD
set FATHOM_CHARTS_API_KEY=fc_test_…

The variable only lasts for that terminal. Each shell reads it its own way: $FATHOM_CHARTS_API_KEY in bash, $env:FATHOM_CHARTS_API_KEY in PowerShell, %FATHOM_CHARTS_API_KEY% in cmd. A variable written the wrong way sends an empty or literal Authorization header: the connection is then closed with code 4001. With the SDK, a missing variable throws a FathomChartsError with code CONFIGURATION from the constructor.

Never put the key in code that runs in a browser. For a web page, see Browser access.

2. Open a connection

For a first try, the wscat command-line tool is all you need (-y skips the install prompt of npx):

BASH
npx -y wscat -c wss://stream.fathomcharts.com/v1 -H "Authorization: Bearer $FATHOM_CHARTS_API_KEY"

In PowerShell:

POWERSHELL
npx -y wscat -c wss://stream.fathomcharts.com/v1 -H "Authorization: Bearer $env:FATHOM_CHARTS_API_KEY"

In cmd:

CMD
npx -y wscat -c wss://stream.fathomcharts.com/v1 -H "Authorization: Bearer %FATHOM_CHARTS_API_KEY%"

3. Subscribe

Once connected, send this message. It asks for large aggressive orders of at least 30 contracts (Fathom Trades) on the front-month NQ contract (NQ.front):

JSON
{"t":"subscribe","sub":"bt","instrument":"NQ.front","indicator":"big-trades","params":{"minimum":30},"mode":"confirmed","from":"live"}
  • sub is a name you choose for this subscription. Every message about it carries that name, so you can open several subscriptions on the same connection;
  • mode: "confirmed" sends only completed orders. With mode: "live", you also get the order in progress, updated on every trade;
  • 30 is the default value of minimum: this subscription therefore uses no custom configuration.

Outside an interactive terminal (a script, CI, a coding agent), wscat shows nothing. This Node script sends the same message and prints every message received: in an empty folder, run npm install ws, save it as stream.mjs, then run node stream.mjs (Ctrl+C to stop).

JS
import WebSocket from 'ws';

const ws = new WebSocket('wss://stream.fathomcharts.com/v1', {
  headers: { Authorization: `Bearer ${process.env.FATHOM_CHARTS_API_KEY}` },
});
ws.on('open', () => ws.send(JSON.stringify({
  t: 'subscribe', sub: 'bt', instrument: 'NQ.front', indicator: 'big-trades',
  params: { minimum: 30 }, mode: 'confirmed', from: 'live',
})));
ws.on('message', (data) => console.log(String(data)));
ws.on('close', (code, reason) => console.log('closed', code, String(reason)));

4. Read the messages

Here is what this subscription received at the US cash open (09:30 New York time) on September 24, 2026, with a live key and the Live plan (the snapshot is shortened):

NDJSON
{"t":"hb","cursors":{}}
{"sub":"bt","t":"subscribed","topic":"0dd82a0cf572a15e8fc077c0b5fe3c79","instrument":"NQZ6","tickSizeNanos":"250000000"}
{"sub":"bt","t":"snapshot","cursor":"20720.110992.0","items":[…]}
{"sub":"bt","t":"status","state":"live","lagMs":0}
{"sub":"bt","cursor":"20720.111434.0","t":"upsert","id":"1790256600533489285:0","final":true,"ts":"1790256600535054015","data":{"side":"sell","volume":66,"trades":32,"start":"1790256600533489285","end":"1790256600533489285","first":122041,"last":122017,"price":122017,"vwap":122027.71212121213}}
{"sub":"bt","cursor":"20720.112164.0","t":"upsert","id":"1790256605021635921:0","final":true,"ts":"1790256605033449615","data":{"side":"buy","volume":32,"trades":30,"start":"1790256605021635921","end":"1790256605023486337","first":122101,"last":122114,"price":122114,"vwap":122110.125}}
{"t":"hb","cursors":{"bt":"20720.112164.0"}}

In order:

  1. hb: the heartbeat, sent every 5 seconds to confirm the connection is alive, with the cursor of the last message sent for each subscription. It can arrive before subscribed: the subscription is not in it yet;
  2. subscribed: the subscription is accepted, on the NQZ6 contract that NQ.front designates;
  3. snapshot: the objects that already existed when you subscribed, here the last 32 large orders completed since the session opened (18:00 the day before, New York time). Its cursor is the position of the last update published before your subscribe;
  4. status: the stream is live;
  5. upsert: a new object, here a completed large order.

The first upsert describes a sell order of 66 contracts, filled in 32 trades, that pushed the price down from 122041 to 122017 ticks, or from 30,510.25 to 30,504.25 points (one tick is 0.25 points on NQ, as on ES). Each instrument’s tick size is given by GET /v1/instruments, in billionths, in the tickSizeNanos field ("250000000" for NQ): see Instruments. Every field is documented on the indicator page.

With a test key, you get the same messages 10 minutes late. While the market is closed (weekend, daily break), the status is market_closed and no upsert arrives before it reopens.

Keep the cursor of the last message you received: you will need it to resume after a disconnect.

5. Use the SDK

The @fathom-charts/sdk TypeScript SDK (Node 22+ and browsers) handles authentication, the initial snapshot, resuming after a disconnect and duplicates for you. The package is ESM only: your project must declare "type": "module" in its package.json. In an empty folder:

BASH
npm init -y
npm pkg set type=module
npm install @fathom-charts/sdk ws
mkdir src

These commands are the same in PowerShell and cmd. In Node, the ws package opens the connection with the Authorization header; browsers use their native WebSocket.

Then generate the types of each indicator’s data from the catalog (GET /v1/indicators, no authentication):

BASH
curl "https://api.fathomcharts.com/v1/indicators" -o catalog.json
npx fathom-charts-types catalog.json src/fathom-charts-types.ts

In PowerShell, type curl.exe instead of curl (in Windows PowerShell, curl is another command).

Then save this program as src/big-trades.ts:

TS
import { FathomChartsStream } from '@fathom-charts/sdk';
import type { BigTradesData } from './fathom-charts-types.js';

const stream = new FathomChartsStream({
  url: 'wss://stream.fathomcharts.com/v1',
  apiKey: process.env.FATHOM_CHARTS_API_KEY!,
});

const bigTrades = stream.subscribe<BigTradesData>({
  instrument: 'NQ.front',
  indicator: 'big-trades',
  params: { minimum: 30 },
  mode: 'confirmed',
});

for await (const event of bigTrades) {
  if (event.type === 'snapshot') console.log('snapshot', event.items.length, 'objects');
  if (event.type === 'status') console.log('status', event.state);
  if (event.type === 'upsert') {
    console.log(event.data.side, event.data.volume, event.data.price);
  }
}

And run it, in the terminal where the key is set:

BASH
npx -y tsx src/big-trades.ts

The program runs until you stop it with Ctrl+C. Several minutes can go by without a large order, especially outside US cash hours: the status printed at the start already confirms that the stream works.

tsx runs the program without checking types. To check them (in your editor, or with npx tsc), also install npm install -D typescript @types/node and add this tsconfig.json at the root of the folder:

JSON
{ "compilerOptions": { "module": "nodenext", "target": "es2022", "types": ["node"], "strict": true, "noEmit": true } }

The SDK hands you the subscription’s messages as events whose type field is the message name: subscribed, snapshot, upsert, remove, status and reset. hb, notice and pong are handled by the SDK and not handed to you; an error ends the loop with a FathomChartsError exception. Every option and method: SDK.

6. Run the same request over history

The same instrument, indicator and params work over a past period. Times are timestamps in nanoseconds since January 1, 1970 (UTC), sent as strings. Here, the last 5 completed days: REST history stops at midnight UTC (the current day is not in it yet), 5 days always overlap at least 3 sessions, at least 2 of them complete, and the range stays within the Sandbox’s 7 days. It therefore works with a test key, or with a live key without a plan or with the Historical plan (with the Live plan alone, history is rejected with 403 FORBIDDEN). "mode": "confirmed" keeps only completed orders.

This request costs 1 compute unit per trade of the 5 days, one to a few million compute units on NQ: estimate it first, for free, by sending the same body to /v1/indicator-queries/estimate (see Estimate the cost).

BASH
TODAY=$(( $(date +%s) / 86400 * 86400 ))
FROM="$((TODAY - 5 * 86400))000000000"
TO="${TODAY}000000000"

curl https://api.fathomcharts.com/v1/indicator-queries \
  -H "Authorization: Bearer $FATHOM_CHARTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"instrument\":\"NQ.front\",\"indicator\":\"big-trades\",\"params\":{\"minimum\":30},\"mode\":\"confirmed\",\"from\":\"$FROM\",\"to\":\"$TO\"}"

You get a page of results (items), its cost in compute units (computeUnits, charged against your monthly compute budget) and a next field. A page holds at most 1,000 results by default: as long as next is not null, send the same request with "cursor": "<next value>" to get the next page. With the SDK, the loop reads as follows (in src/history.ts, run with npx -y tsx src/history.ts):

TS
import { FathomChartsRest, type Page } from '@fathom-charts/sdk';
import type { BigTradesData } from './fathom-charts-types.js';

const rest = new FathomChartsRest({ baseUrl: 'https://api.fathomcharts.com', apiKey: process.env.FATHOM_CHARTS_API_KEY! });

// The last 5 completed UTC days, in nanoseconds.
const today = Math.floor(Date.now() / 86_400_000) * 86_400;
const query = {
  instrument: 'NQ.front',
  indicator: 'big-trades',
  params: { minimum: 30 },
  mode: 'confirmed' as const,
  from: `${today - 5 * 86_400}000000000`,
  to: `${today}000000000`,
};

let next: string | null = null;
let computeUnits = 0;
do {
  const page: Page<BigTradesData> = await rest.page<BigTradesData>(next === null ? query : { ...query, cursor: next });
  for (const m of page.items) {
    if (m.t === 'upsert' && m.data) console.log(m.cursor, m.data.side, m.data.volume, m.data.price);
  }
  computeUnits += page.computeUnits;
  next = page.next;
} while (next !== null);
console.log('compute units:', computeUnits);

Each object has the same id and the same cursor as when the real-time stream published it. In live mode (the default), history also includes the intermediate versions (final: false) published while each object was being built. rest.history() runs this loop for you and yields the results one by one. See History.

Next steps

  • Authentication: restrict a key, rotate it, open the stream from a browser.
  • Real time: keep your state in sync, resume after a disconnect.
  • SDK: every option and method of the TypeScript SDK.
  • Indicator catalog: parameters and data for every indicator.
  • Use with an LLM: give this documentation to your AI assistant or coding agent.