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

# Initialization

> Connect to the SX Bet real-time WebSocket API using Centrifuge

## Install

<CodeGroup>
  ```bash npm theme={null}
  npm install centrifuge
  ```

  ```bash pip theme={null}
  pip install centrifuge-python requests
  ```
</CodeGroup>

Centrifugo provides official client SDKs for most platforms:

| SDK                                                                   | Language / Platform                         |
| --------------------------------------------------------------------- | ------------------------------------------- |
| [centrifuge-js](https://github.com/centrifugal/centrifuge-js)         | JavaScript — browser, Node.js, React Native |
| [centrifuge-python](https://github.com/centrifugal/centrifuge-python) | Python (asyncio)                            |
| [centrifuge-go](https://github.com/centrifugal/centrifuge-go)         | Go                                          |
| [centrifuge-dart](https://github.com/centrifugal/centrifuge-dart)     | Dart / Flutter                              |
| [centrifuge-swift](https://github.com/centrifugal/centrifuge-swift)   | Swift (iOS)                                 |
| [centrifuge-java](https://github.com/centrifugal/centrifuge-java)     | Java / Android                              |
| [centrifuge-csharp](https://github.com/centrifugal/centrifuge-csharp) | C# (.NET, MAUI, Unity)                      |

For the full list including community SDKs, see the [Centrifugo client SDK docs](https://centrifugal.dev/docs/transports/client_sdk).

## Connect

Fetch a token using your API key, then instantiate and connect the Centrifuge client. You only need one client instance — all channel subscriptions are multiplexed over the single connection. If you need more than 512 subscriptions, create additional client instances (each connection supports up to 512 channels). See [Limits](/api-reference/centrifugo-overview#limits) for details.

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { Centrifuge } from "centrifuge";

  const RELAYER_URL = "https://api.sx.bet"; // Mainnet — use https://api.toronto.sx.bet for testnet
  const WS_URL = "wss://realtime.sx.bet/connection/websocket"; // Mainnet — use wss://realtime.toronto.sx.bet/connection/websocket for testnet

  async function fetchCentrifugoToken(apiKey) {
    const res = await fetch(`${RELAYER_URL}/user/realtime-token/api-key`, {
      headers: { "x-api-key": apiKey },
    });
    if (!res.ok) {
      const body = await res.text();
      throw new Error(`Token endpoint returned ${res.status}: ${body}`);
    }
    const { token } = await res.json();
    return token;
  }

  const client = new Centrifuge(WS_URL, {
    getToken: () => fetchCentrifugoToken(YOUR_API_KEY),
  });

  client.connect();
  ```

  ```python Python theme={null}
  import asyncio
  import os
  import requests
  from centrifuge import Client

  RELAYER_URL = "https://api.sx.bet"  # Mainnet — use https://api.toronto.sx.bet for testnet
  WS_URL = "wss://realtime.sx.bet/connection/websocket"  # Mainnet — use wss://realtime.toronto.sx.bet/connection/websocket for testnet

  def fetch_token():
      res = requests.get(
          f"{RELAYER_URL}/user/realtime-token/api-key",
          headers={"x-api-key": os.environ["SX_API_KEY"]},
      )
      if not res.ok:
          body = res.text
          raise Exception(f"Token endpoint returned {res.status_code}: {body}")
      return res.json()["token"]

  async def main():
      client = Client(WS_URL, get_token=fetch_token)
      await client.connect()
      await asyncio.Future()  # keep running

  asyncio.run(main())
  ```
</CodeGroup>

## Subscribe to a channel

Once connected, create a subscription for the channel you want. All channel pages in this section use this same pattern — replace `"channel:name"` with the channel name format documented on each page.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const sub = client.newSubscription("channel:name", { positioned: true, recoverable: true });

  sub.on("publication", (ctx) => {
    const data = ctx.data;
    // handle incoming message
  });

  sub.subscribe();
  ```

  ```python Python theme={null}
  import asyncio
  from centrifuge import Client, PublicationContext, SubscriptionEventHandler

  async def on_publication(ctx: PublicationContext) -> None:
      print(ctx.data)

  async def main():
      client = Client(
          "wss://realtime.sx.bet/connection/websocket",
          token="YOUR_TOKEN",  # from /user/realtime-token/api-key
      )
      await client.connect()
      handler = SubscriptionEventHandler(on_publication=on_publication)
      sub = client.new_subscription("channel:name", handler)
      await sub.subscribe()
      await asyncio.Future()  # keep running

  asyncio.run(main())
  ```
</CodeGroup>

<Tip>
  Pass `positioned: true, recoverable: true` together on channels with history enabled to get at-least-once delivery across reconnects. See [Namespace history capabilities](/api-reference/centrifugo-overview#namespace-history-capabilities) for which channels support this, and [Best Practices](/api-reference/centrifugo-best-practices) for how to handle recovery outcomes.
</Tip>

Each publication event exposes a `ctx` object with the following structure:

```json theme={null}
{
  "channel": "parlay_markets:global",
  "data": { },
  "tags": {
    "publishedAt": "1773869618503",
    "messageId": "5db68f78-8442-4530-8476-62495333e9ee"
  }
}
```

`ctx.data` is the channel payload documented on each channel's reference page. `ctx.tags.messageId` is a UUID present on every publication — use it to deduplicate messages during history recovery (see [Real-time Data → Dedup](/developers/real-time#dedup)).

## Cleanup

When you no longer need a subscription, clean it up to free resources:

<CodeGroup>
  ```javascript JavaScript theme={null}
  sub.unsubscribe();
  sub.removeAllListeners();
  client.removeSubscription(sub);
  ```

  ```python Python theme={null}
  await sub.unsubscribe()
  client.remove_subscription(sub)
  ```
</CodeGroup>
