> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parlayx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Handle typed server frames and connection lifecycle events with on()

Everything the client surfaces flows through `on(type, handler)`. There are two
kinds of event: **server frames** (keyed by the frame's `type`) and
**lifecycle events** (connection-level signals the client raises itself). The
handler payload is typed per event — `on("snapshot", …)` gives you a
`SnapshotFrame`, `on("reconnecting", …)` gives you `{ attempt, delayMs }`.

```ts theme={null}
stream.on("snapshot", (frame) => {
  /* frame is a SnapshotFrame: frame.subscriptionId, frame.bids, frame.asks, frame.seq… */
});
```

`on` returns an **unsubscribe function** — call it to remove that handler:

```ts theme={null}
const off = stream.on("trade", (frame) => console.log(frame));
off(); /* stop listening */
```

## Server frames

Every frame carries `type`, a `v` version, and a `serverTimestamp`. The table
lists the additional fields you'll use most; the WebSocket API's
[Message catalog](/streaming/messages) documents each frame in full.

| Event           | When it fires                                             | Key fields                                                  |
| --------------- | --------------------------------------------------------- | ----------------------------------------------------------- |
| `welcome`       | Once, right after connect                                 | `customerId`, `connectionId`, `activeConnections`, `limits` |
| `subscribed`    | Ack of a `subscribe` (one per market)                     | `subscriptionId`, `market`, `channel`, `snapshotPending`    |
| `unsubscribed`  | Ack of an `unsubscribe`                                   | `subscriptionId`, `market`, `channel`                       |
| `snapshot`      | Full book state, once per book subscription               | `subscriptionId`, `seq`, `bids`, `asks`, `status`           |
| `delta`         | Incremental book changes                                  | `subscriptionId`, `seq`, `changes`                          |
| `trade`         | A public trade on the `trade` channel                     | `subscriptionId` and trade fields                           |
| `status`        | A subscription's health changed                           | `subscriptionId`, `state`, `reason?`                        |
| `error`         | A request failed or a subscription errored                | `code`, `message`, `subscriptionId?`, `market?`             |
| `goodbye`       | Server is about to close the connection                   | `reason`                                                    |
| `subscriptions` | Reply to `list()` — the connection's active subscriptions | the subscription list                                       |
| `pong`          | Reply to a `ping()`                                       | `requestId?`                                                |

A few notes:

* **`snapshot` / `delta`** are the orderbook. Apply the snapshot first, then each
  delta (a `change` with `size: 0` deletes that price level). `seq` is a
  per-subscription monotonic counter for detecting gaps — see
  [Orderbook channel](/streaming/orderbook).
* **`status`** reports `live`, `resyncing`, `closed`, `unsupported`, or
  `unavailable`. When the server retires a subscription (`closed`/`unsupported`)
  the client drops it from its resubscribe set so it isn't replayed on reconnect.
* **`error`** frames raised during subscription creation carry the `market` and
  `channel` that failed (there's no `subscriptionId` yet); the client prunes that
  market so it won't be retried on reconnect. See
  [Errors](/streaming/errors) for the `code` values.
* **`goodbye`** precedes a close. Some reasons are terminal — see
  [Reconnection & lifecycle](/sdk/stream/reconnection).

## Lifecycle events

These are raised by the client, not sent by the server. They're distinct from the
server's `error` and `goodbye` frames.

| Event          | Payload                | Meaning                                                             |
| -------------- | ---------------------- | ------------------------------------------------------------------- |
| `open`         | —                      | The socket opened (before the `welcome` frame).                     |
| `close`        | `{ code, reason }`     | The socket closed. The client may reconnect (see below).            |
| `socketError`  | the transport error    | A transport-level error (distinct from a server `error` frame).     |
| `reconnecting` | `{ attempt, delayMs }` | A reconnect was scheduled; `attempt` counts consecutive tries.      |
| `terminated`   | `{ reason }`           | The client gave up and will **not** reconnect. Create a new client. |

```ts theme={null}
stream.on("open", () => console.log("connected"));
stream.on("reconnecting", ({ attempt, delayMs }) =>
  console.warn(`reconnecting (attempt ${attempt}) in ${delayMs}ms`),
);
stream.on("terminated", ({ reason }) => console.error(`stream terminated: ${reason}`));
```

See [Reconnection & lifecycle](/sdk/stream/reconnection) for exactly when
`reconnecting` versus `terminated` fires.
