> For the complete documentation index, see [llms.txt](https://docs.strikelabs.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.strikelabs.app/api-reference/streaming.md).

# WebSocket feed

`GET /ws` is a WebSocket. Connect with your token in the query string, then listen — the server sends, the client does not.

```
wss://venue.example/ws?token=YOUR_TOKEN
```

Browsers cannot set headers on a WebSocket, which is why the token goes in the query string. It stays inside TLS, and the venue's access log format does not record query strings.

Anything a client sends is control traffic only (ping, pong, close). Orders go over REST: an order arriving on a socket would need its own idempotency story, and [`/v1/order`](/api-reference/exchange.md#order) already has one.

Frames are pushed on a short tick (250ms by default) and only when something changed. When nobody is connected the broadcaster does no work at all.

## Frames

Every frame is a JSON object with a `type`. Public frames go to every client; account frames go **only** to the sockets holding that account's token.

| `type`    | Scope  | Contents                                                                 |
| --------- | ------ | ------------------------------------------------------------------------ |
| `account` | you    | Your account. Sent first on connect, then whenever your positions change |
| `spots`   | public | Every symbol's spot, when any of them moved                              |
| `tape`    | public | One public print                                                         |
| `fill`    | you    | One of **your** fills                                                    |
| `orders`  | you    | **Your** resting orders, in full                                         |

### `fill`

```json
{ "type": "fill", "fill": {
    "seriesId": "META-1786752000-C-600",
    "side": "buy", "price": 6.1, "qty": 2,
    "ts": 1788393600123, "taker": true,
    "signer": "0xabc…"
}}
```

`side` is the side **you** traded, so a maker sees the opposite of the print. `taker` says whether you were the aggressor. `signer` is present only when the originating order was signed.

Oldest first, so appending frames in arrival order gives you your history the right way round.

Fills sharing a millisecond arrive together, because the stream's cursor is a timestamp rather than a sequence number. If you keep your own cursor, advance it to the newest `ts` you received — not by one millisecond.

### `orders`

```json
{ "type": "orders", "orders": [
    { "id": 8413, "seriesId": "META-1786752000-C-600",
      "side": "buy", "price": 5.0, "remaining": 1.5 }
]}
```

A **full snapshot**, not a diff, sent whenever the set changes. An order's life is create → partially fill → cancel, and rebuilding that from deltas over a socket that can drop frames is how a client ends up displaying an order that no longer exists. Ordered by `id`, stably, so diffing two snapshots shows only real changes.

`remaining` is what is still working, not the original size. An empty array means you have nothing resting.

## Reconnecting

The first frame after connect is your full `account`, not the next delta, because a client that reconnects has missed everything sent while it was away.

You will still have missed **fills** in that window — the stream resumes from now, not from where you dropped, so that a busy account's first frame is not its entire history. Reconcile with [`/v1/fills`](/api-reference/exchange.md#fills) after any reconnect if your bookkeeping depends on seeing every fill.

## Being dropped

Two ways the server hangs up on you:

* **You stopped answering pings.** It pings every 20s and gives up after 90s of silence.
* **You stopped reading.** A client whose queue reaches 512 frames is dropped rather than buffered further: one slow consumer must not become the venue's memory problem. If this happens, you are not draining the socket fast enough — do your work off the socket thread.

## Polling, which still works

The socket does not cover books or chains. Those are still polled, and different data changes at different rates:

| What                | Endpoint                                    | Suggested interval                   |
| ------------------- | ------------------------------------------- | ------------------------------------ |
| The chain on screen | [`/v1/chain`](/api-reference/info.md#chain) | 1–3s, only the visible expiry        |
| One contract's book | [`/v1/book`](/api-reference/info.md#book)   | 1–2s                                 |
| Underlying prices   | [`/v1/meta`](/api-reference/info.md#meta)   | 2–5s, or take `spots` off the socket |
| Prints              | [`/v1/tape`](/api-reference/info.md#tape)   | 2–3s, or take `tape` off the socket  |

Two things make this cheaper than it looks:

**Orders return your account.** A successful `/v1/order` includes the updated account in its response, so you never need to poll `/v1/me` to learn the result of your own trade.

**Listings are nearly static.** [`/v1/series`](/api-reference/info.md#series) changes only when the daily roll lists new contracts. Fetch it once at startup and refresh it on a timer measured in minutes, not seconds.

## What to avoid

Do not poll `/v1/chain` for every listed expiry. A symbol carries a dozen expiries and over a thousand series; pricing them all, repeatedly, is the one access pattern that will hurt. Fetch the expiry your user is looking at.

Do not poll `/v1/fills` on a timer while holding a socket. The `fill` frames are the same data, pushed.

## Planned

Push delivery for books and chains. The engine already tracks which books are dirty on every fill, so the broadcast has a natural hook — it simply has not been built. When it lands it will be documented here, and polling will keep working.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.strikelabs.app/api-reference/streaming.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
