> ## 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.

# Connection lifecycle

> The welcome frame, connection limits, keepalive, disconnects, and reconnect guidance

A connection runs from the [`welcome`](#welcome) frame the server sends on
connect to the [`goodbye`](#connection-lifetime-and-goodbye) it sends just
before closing. This page covers everything that happens at the connection
level — independent of any individual subscription.

## `welcome`

Immediately after the upgrade succeeds, the server sends a `welcome` frame:

```json theme={null}
{
  "type": "welcome",
  "v": 1,
  "serverTimestamp": 1748020034123,
  "customerId": "9a4b7e2c-1a64-4dca-9d6e-1b8c2d3f4a5b",
  "connectionId": "1d3a9c44-cf21-4f33-9211-2b9b1adf67e8",
  "activeConnections": 1,
  "limits": { "maxSubscriptionsPerConnection": 200, "maxConnections": 20, "connectionTtlSeconds": 28800 }
}
```

| Field               | Meaning                                                                                                    |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| `customerId`        | Your account identifier.                                                                                   |
| `connectionId`      | This connection's identifier. **Quote it in any support request** so we can find your session in our logs. |
| `activeConnections` | How many connections your account currently holds, including this one.                                     |
| `limits`            | The caps that apply to this connection — see below.                                                        |

Treat `welcome` as the signal that the connection is ready: wait for it before
sending your first [`subscribe`](/streaming/subscriptions#subscribe).

## Connection limits

The `welcome.limits` object reports the caps for your connection:

| Field                           | Meaning                                                                                                                                                                      |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `maxSubscriptionsPerConnection` | Maximum active `(market, channel)` subscriptions on this connection (currently 200). Exceeding it yields a [`QUOTA_EXCEEDED`](/streaming/errors#error-codes) error.          |
| `maxConnections`                | Maximum simultaneous connections for your account across the whole service (currently 20). A connect attempt past it is rejected with HTTP `429` at the WebSocket handshake. |
| `connectionTtlSeconds`          | The connection's maximum lifetime — see [Connection lifetime](#connection-lifetime-and-goodbye).                                                                             |

**Scaling past the subscription cap is by design: open multiple connections.**
Spread your markets across connections; one stream key authenticates all of
them, up to your `maxConnections`. The defaults give one account up to 20 ×
200 = 4,000 simultaneous `(market, channel)` subscriptions — if you need more,
reach out and we can raise your account's connection limit.

Dropped or unresponsive connections are cleaned up automatically within about a
minute and stop counting against `maxConnections`.

## Keepalive

The server sends WebSocket-protocol pings every 30 seconds; any standard
WebSocket client answers them automatically. A connection that stops answering
is treated as idle and closed with [`idleTimeout`](#connection-lifetime-and-goodbye).

You can also send an application-level `ping` and get a `pong` back — useful as
an explicit liveness check or to keep an otherwise-quiet connection active:

```json theme={null}
{ "type": "ping", "requestId": "…" }
```

```json theme={null}
{ "type": "pong", "v": 1, "serverTimestamp": 1748020034300, "requestId": "…" }
```

The `requestId` you send is echoed on the `pong`. This is independent of the
WebSocket-protocol pings above.

## Connection lifetime and `goodbye`

Just before the server closes a connection, it sends a `goodbye` frame with a
`reason`, then closes the socket. Always reconnect on a `goodbye` or any
unexpected close.

```json theme={null}
{ "type": "goodbye", "v": 1, "serverTimestamp": 1748020034400, "reason": "ttl" }
```

| `reason`       | Meaning                                                                                             | What to do                                                                                                                |
| -------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `ttl`          | The connection reached `connectionTtlSeconds`.                                                      | Reconnect. Schedule this proactively before the TTL to avoid a visible gap.                                               |
| `shutdown`     | The serving task is shutting down (deploy or scale-in).                                             | Reconnect; you land on another task. Data keeps flowing briefly after the warning, so you have time to reconnect cleanly. |
| `noActiveSubs` | The connection sat with zero subscriptions past a grace period.                                     | Reconnect when you next need data; keep at least one subscription otherwise.                                              |
| `idleTimeout`  | The connection was idle / unresponsive to pings.                                                    | Reconnect; make sure your client answers WebSocket pings.                                                                 |
| `authRevoked`  | The stream key was revoked.                                                                         | Stop reconnecting with that key; obtain a new one.                                                                        |
| `kicked`       | The connection was closed by the server (e.g. a persistently slow reader that fell too far behind). | Reconnect; ensure you're draining the socket fast enough.                                                                 |

## Reconnect guidance

* Reconnect with backoff on any close, but reconnect **immediately** (after a
  short jitter) on `ttl` and `shutdown` — those are routine.
* A `503` during the upgrade means the gateway is at capacity. Back off briefly
  and retry; you'll be routed to fresh capacity.
* A `429` during the upgrade means your account is at its `maxConnections`
  limit. Retrying does not help — close a connection you no longer need (or
  wait \~90 seconds after an ungraceful drop for its slot to free), and contact
  us if you need the limit raised.
* On reconnect, re-[`subscribe`](/streaming/subscriptions#subscribe) to your
  markets. Each book subscription replays a fresh `snapshot`, so your state
  rebuilds automatically. There is no resume-from-offset to manage.
* Don't reconnect on `authRevoked`; the key is dead.
