# 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](https://fathomcharts.com/login) 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](https://fathomcharts.com/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](https://fathomcharts.com/docs/billing.md) 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](https://fathomcharts.com/docs/authentication.md#browser-access).

## 2. Open a connection

For a first try, the [wscat](https://github.com/websockets/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](https://fathomcharts.com/docs/indicators/big-trades.md)) 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](https://fathomcharts.com/docs/limits.md#how-limits-are-counted).

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](https://fathomcharts.com/docs.md#instruments). Every field is documented on the [indicator](https://fathomcharts.com/docs/indicators/big-trades.md) 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](https://fathomcharts.com/docs/websocket.md#cursors-and-resuming) 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](https://fathomcharts.com/docs/sdk.md).

## 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](https://fathomcharts.com/docs/history.md#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](https://fathomcharts.com/docs/limits.md#how-limits-are-counted)) 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](https://fathomcharts.com/docs/history.md).

## Next steps

- [Authentication](https://fathomcharts.com/docs/authentication.md): restrict a key, rotate it, open the stream from a browser.
- [Real time](https://fathomcharts.com/docs/websocket.md): keep your state in sync, resume after a disconnect.
- [SDK](https://fathomcharts.com/docs/sdk.md): every option and method of the TypeScript SDK.
- [Indicator catalog](https://fathomcharts.com/docs/indicators.md): parameters and data for every indicator.
- [Use with an LLM](https://fathomcharts.com/docs/llm.md): give this documentation to your AI assistant or coding agent.
