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

# Connection and limits

> WebSocket connection lifecycle, rate limits, and protocol requirements.

Connection URLs, protocol requirements, rate limits, and reconnection strategy for the XOXNO Relayer.

## Connection URLs

| Endpoint                           | Protocol        | Purpose                                              |
| ---------------------------------- | --------------- | ---------------------------------------------------- |
| `wss://relayer.xoxno.com/ws`       | WebSocket (TLS) | Full-duplex: subscribe, relay, broadcast             |
| `wss://relayer.xoxno.com/ws/stats` | WebSocket (TLS) | Read-only network stats stream (no subscribe needed) |
| `https://relayer.xoxno.com`        | HTTPS           | REST API base URL                                    |

All WebSocket messages are JSON. The Relayer accepts binary frames for proto broadcast passthrough.

## Limits at a glance

| Parameter                         | Value                  |
| --------------------------------- | ---------------------- |
| Max topics per connection         | 64                     |
| Rate limit (control messages)     | 64 per 5-second window |
| Max message size                  | 4 MB                   |
| Ping/pong heartbeat interval      | 30 seconds             |
| Max subscribers per address topic | 100                    |
| Max unique address entries        | 10,000                 |

## Ping/pong heartbeat

The Relayer sends a WebSocket `Ping` frame every 30 seconds. Your client must respond with a `Pong` frame to keep the connection alive. Most WebSocket libraries handle this automatically.

If the Relayer receives no `Pong` response, it closes the connection. If your library does not auto-respond to pings, implement a pong handler:

```ts theme={"system"}
// Most browser WebSocket implementations handle ping/pong automatically.
// For Node.js with the 'ws' library:
const WebSocket = require("ws");
const ws = new WebSocket("wss://relayer.xoxno.com/ws");

ws.on("ping", () => {
  ws.pong();
});
```

## Topic limits

Each connection can hold up to **64 active topic subscriptions** simultaneously. This limit covers all topic types combined: `gasStats`, `networkStats`, `accounts`, `address/{bech32}`, and `tx-status/{hash}`.

When you reach the limit, the Relayer returns:

```json theme={"system"}
{
  "action": "subscribe",
  "status": "fail",
  "reason": "topic limit reached"
}
```

To free slots:

* Unsubscribe from topics you no longer need.
* Unsubscribe from `tx-status/{hash}` topics once the transaction confirms.

## Rate limiting

The Relayer enforces a rate limit of **64 control messages per 5-second window**. Control messages are `subscribe` and `unsubscribe` actions. The `relay` and `broadcast` actions use backpressure from the internal aggregator instead of this rate limit.

If you exceed the rate limit:

```json theme={"system"}
{
  "action": "subscribe",
  "status": "fail",
  "reason": "rate limit exceeded"
}
```

<Warning>
  Exceeding 64 control messages within a 5-second window closes the connection. Batch your subscriptions at connection open.
</Warning>

### Staying within the limit

* Subscribe to all topics in a single burst at connection open (up to 64 topics).
* Avoid subscribe/unsubscribe churn during normal operation.
* If you need to rotate address subscriptions, batch the unsubscribes and subscribes together.

## Message size

The maximum WebSocket message size is **4 MB**. The Relayer rejects messages exceeding this limit and closes the connection.

This limit applies to both inbound (client-to-server) and outbound (server-to-client) frames. In practice, you approach this limit only when sending large batch payloads.

## Reconnection reconnect handling

WebSocket connections drop over time. Network blips, server deployments, and load balancer timeouts are normal. Design your client for automatic reconnection.

### Exponential backoff

Start at 1 second and double on each consecutive failure, capping at 30 seconds. Reset the delay on successful connection.

```ts theme={"system"}
class RelayerClient {
  constructor() {
    this.topics = new Set();
    this.retryDelay = 1000;
    this.connect();
  }

  connect() {
    this.ws = new WebSocket("wss://relayer.xoxno.com/ws");

    this.ws.onopen = () => {
      this.retryDelay = 1000; // Reset on success

      // Re-subscribe to all tracked topics
      for (const topic of this.topics) {
        this.ws.send(JSON.stringify({
          action: "subscribe",
          topic
        }));
      }
    };

    this.ws.onclose = () => {
      console.log(`Reconnecting in ${this.retryDelay}ms`);
      setTimeout(() => this.connect(), this.retryDelay);
      this.retryDelay = Math.min(this.retryDelay * 2, 30000);
    };

    this.ws.onerror = () => this.ws.close();
  }

  subscribe(topic) {
    this.topics.add(topic);
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify({ action: "subscribe", topic }));
    }
  }

  unsubscribe(topic) {
    this.topics.delete(topic);
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify({ action: "unsubscribe", topic }));
    }
  }
}
```

### Key principles

* **Re-subscribe after every reconnect.** The server discards your subscriptions when the connection drops.
* **Track subscriptions client-side.** Maintain a set of active topics so you can re-subscribe in a burst on reconnect.
* **Cap the backoff at 30 seconds.** Waiting minutes between attempts delays recovery.
* **Handle errors gracefully.** Treat `onerror` as a close trigger, not a fatal event.

## REST endpoint limits

REST endpoints (`/v1/sign`, `/v1/broadcast`, `/v1/network-stats/history`) are rate-limited independently of WebSocket connections. The Relayer applies per-IP rate limiting with a sliding window. If you receive a `429 Too Many Requests` response, back off and retry.

| Endpoint                    | Method | Notes                                                          |
| --------------------------- | ------ | -------------------------------------------------------------- |
| `/v1/sign`                  | POST   | Batch co-signing (Relayer V3). Body: `{ transactions: [...] }` |
| `/v1/broadcast`             | POST   | Batch broadcast. Body: `{ transactions: [...] }`               |
| `/v1/network-stats/history` | GET    | Historical network statistics                                  |
| `/health`                   | GET    | Health check (no rate limit)                                   |
