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

# Connection

> How to connect, message format, keepalive, and reconnection

## Connecting

Open a WebSocket connection to one of the available endpoints:

```
wss://socket.bayse.markets/ws/v1/markets
wss://socket.bayse.markets/ws/v1/user
wss://socket.bayse.markets/ws/v1/realtime
```

The `/ws/v1/user` endpoint requires per-message authentication. See [User orders](/websocket/user-orders) for details.

On a successful connection, the server sends a `connected` message:

```json theme={null}
{
  "type": "connected",
  "status": "connected",
  "clientId": "a1b2c3d4-...",
  "message": "Successfully connected to WebSocket server",
  "timestamp": 1700000000000
}
```

<CodeGroup>
  ```javascript JavaScript theme={null}
  const ws = new WebSocket("wss://socket.bayse.markets/ws/v1/markets");

  ws.addEventListener("open", () => {
    console.log("connected");
  });
  ```

  ```python Python theme={null}
  import asyncio
  import websockets

  async def connect():
      async with websockets.connect("wss://socket.bayse.markets/ws/v1/markets") as ws:
          print("connected")
          async for message in ws:
              print(message)

  asyncio.run(connect())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"log"

  	"github.com/gorilla/websocket"
  )

  func main() {
  	conn, _, err := websocket.DefaultDialer.Dial("wss://socket.bayse.markets/ws/v1/markets", nil)
  	if err != nil {
  		log.Fatal(err)
  	}
  	defer conn.Close()
  	fmt.Println("connected")
  }
  ```
</CodeGroup>

## Message format

All messages are JSON. The server may batch multiple JSON objects into a single WebSocket frame separated by newlines (`\n`). Clients must split on newlines before parsing each line:

```javascript theme={null}
ws.addEventListener("message", (event) => {
  for (const line of event.data.split("\n")) {
    if (line.trim()) {
      const msg = JSON.parse(line);
      // handle msg
    }
  }
});
```

### Client messages

Messages sent from the client to the server follow this structure:

```json theme={null}
{
  "type": "subscribe",
  "channel": "prices",
  "eventId": "EVENT_ID",
  "marketId": "MARKET_ID",
  "marketIds": ["MARKET_ID"],
  "currency": "USD",
  "symbols": ["BTCUSDT"],
  "room": "ROOM_NAME"
}
```

Only include the fields relevant to the channel you are using. The `type` field is always required.

| Field       | Type      | Description                                                                     |
| ----------- | --------- | ------------------------------------------------------------------------------- |
| `type`      | string    | **Required.** One of `subscribe`, `unsubscribe`, `ping`.                        |
| `channel`   | string    | Subscription channel (e.g., `activity`, `prices`, `orderbook`, `asset_prices`). |
| `eventId`   | string    | Prediction event UUID. Required for `activity` and `prices`.                    |
| `marketId`  | string    | Market UUID. Optional filter for `activity`.                                    |
| `marketIds` | string\[] | Market UUIDs (max 10). Required for `orderbook`.                                |
| `currency`  | string    | `USD` or `NGN`. Optional for `orderbook`.                                       |
| `symbols`   | string\[] | Asset symbols (e.g., `BTCUSDT`). Required for `asset_prices`.                   |
| `room`      | string    | Room name. Required for `unsubscribe`.                                          |

### Server messages

Messages sent from the server to the client:

```json theme={null}
{
  "type": "price_update",
  "data": { ... },
  "timestamp": 1700000000000
}
```

| Field       | Type   | Description                                    |
| ----------- | ------ | ---------------------------------------------- |
| `type`      | string | The event type (e.g., `price_update`).         |
| `data`      | object | Event payload. Varies by event type.           |
| `timestamp` | number | Unix timestamp (milliseconds).                 |
| `status`    | string | Present on the `connected` message.            |
| `clientId`  | string | Your assigned client ID.                       |
| `message`   | string | Human-readable text when provided.             |
| `room`      | string | Room name for subscribe/unsubscribe responses. |

## Subscribing and unsubscribing

Subscribe to a channel by sending a `subscribe` message with the required fields:

```json theme={null}
{ "type": "subscribe", "channel": "prices", "eventId": "EVENT_ID" }
```

Unsubscribe by sending an `unsubscribe` message with the room name:

```json theme={null}
{ "type": "unsubscribe", "room": "prices:EVENT_ID" }
```

The server confirms with an `unsubscribed` message:

```json theme={null}
{
  "type": "unsubscribed",
  "room": "prices:EVENT_ID",
  "message": "Unsubscribed from: prices:EVENT_ID",
  "timestamp": 1700000000000
}
```

### Room naming

Room names are constructed from the channel and subscription parameters:

| Subscription                    | Room name                       |
| ------------------------------- | ------------------------------- |
| Activity feed                   | `activity:<eventId>`            |
| Activity feed (market-specific) | `activity:<eventId>:<marketId>` |
| Price updates                   | `prices:<eventId>`              |
| Orderbook (USD)                 | `orderbook:<marketId>`          |
| Orderbook (NGN)                 | `orderbook:<marketId>:NGN`      |
| Orders                          | `orders:<userId>:<marketId>`    |
| Asset prices                    | `asset_prices:<SYMBOL>`         |

## Keepalive

The server sends WebSocket-level ping frames every \~54 seconds. Most WebSocket libraries handle pong replies automatically.

You can also send an application-level ping to verify the connection is alive:

```json theme={null}
{ "type": "ping" }
```

The server replies with:

```json theme={null}
{ "type": "pong", "timestamp": 1700000000000 }
```

<Warning>
  If the server does not receive a pong within 60 seconds, the connection is closed. Ensure your client handles WebSocket ping/pong frames.
</Warning>

## Reconnection

Connections can drop due to network issues, server restarts, or idle timeouts. Implement reconnection with exponential backoff:

<CodeGroup>
  ```javascript JavaScript theme={null}
  function connect() {
    const ws = new WebSocket("wss://socket.bayse.markets/ws/v1/markets");
    let attempt = 0;

    ws.addEventListener("open", () => {
      attempt = 0;
      // re-subscribe to channels
    });

    ws.addEventListener("close", () => {
      const delay = Math.min(1000 * 2 ** attempt, 30000);
      attempt++;
      setTimeout(connect, delay);
    });

    return ws;
  }
  ```

  ```python Python theme={null}
  import asyncio
  import websockets

  async def connect():
      attempt = 0
      while True:
          try:
              async with websockets.connect("wss://socket.bayse.markets/ws/v1/markets") as ws:
                  attempt = 0
                  # re-subscribe to channels
                  async for message in ws:
                      print(message)
          except websockets.ConnectionClosed:
              delay = min(2 ** attempt, 30)
              attempt += 1
              await asyncio.sleep(delay)
  ```

  ```go Go theme={null}
  func connectWithRetry() {
  	attempt := 0
  	for {
  		conn, _, err := websocket.DefaultDialer.Dial(
  			"wss://socket.bayse.markets/ws/v1/markets", nil,
  		)
  		if err != nil {
  			delay := time.Duration(math.Min(math.Pow(2, float64(attempt)), 30)) * time.Second
  			attempt++
  			time.Sleep(delay)
  			continue
  		}
  		attempt = 0
  		// re-subscribe to channels
  		handleConnection(conn)
  	}
  }
  ```
</CodeGroup>

## Limits

| Limit        | Value              | Scope          |
| ------------ | ------------------ | -------------- |
| Message rate | 10 messages/second | Per connection |

WebSocket upgrades are rate-limited per IP.
