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

# Real-time channels with the SportsX C# WebSocket

> Subscribe to Phoenix channels for live portfolio balance, order state changes, trade fills, market price ticks, and settlement events in your .NET app.

The SportsX exchange pushes state changes over Phoenix WebSocket channels. `STX.Sdk` wraps each topic in a strongly-typed class with event callbacks and handles the low-level details for you: JWT attachment on the connection URL, 30-second heartbeats, exponential-backoff reconnection, and automatic topic resubscription after a reconnect.

## Available channels

| Channel class                        | Topic                                        | What it pushes                        |
| ------------------------------------ | -------------------------------------------- | ------------------------------------- |
| `STXPortfolioChannel`                | `portfolio:{user_id}`                        | Available balance, escrow, total P\&L |
| `STXActiveOrdersChannel`             | `active_orders:{user_id}`                    | Order state transitions               |
| `STXActiveTradesChannel`             | `active_trades:{user_id}`                    | Fills as they land                    |
| `STXActiveSettlementsChannelWrapper` | `active_settlements:{user_id}`               | Market settlement events              |
| `STXPositionsChannel`                | `active_positions:{user_id}`                 | Position changes                      |
| `STXUserInfoChannel`                 | `user_info:{user_id}`                        | Profile and account updates           |
| `STXMarketChannel`                   | `markets` / `market_info` / `market_updates` | Market state and price ticks          |

All channel classes are registered as **singletons** in the DI container, so the socket and subscription state are shared across your app.

## Connect a channel

The pattern is the same for every channel: resolve it, register event handlers, then call `ConnectAsync`. `ConnectAsync` is idempotent — calling it more than once is a no-op.

```csharp theme={null}
var portfolio = serviceProvider.GetRequiredService<STXPortfolioChannel>();

portfolio.OnSummary += summary =>
    Console.WriteLine($"Available: {summary.AvailableBalance}c  Escrow: {summary.Escrow}c");

portfolio.OnUpdate += summary =>
    Console.WriteLine($"Balance tick: {summary.AvailableBalance}c");

await portfolio.ConnectAsync();
```

## Portfolio channel

The portfolio channel streams your account's financial state. The server pushes a `summary` event on join and an `update` event on every state change (order placed, fill, deposit, withdrawal, settlement):

```csharp theme={null}
public class BalanceTracker
{
    private readonly STXPortfolioChannel _portfolio;
    public long AvailableBalance { get; private set; }

    public BalanceTracker(STXPortfolioChannel portfolio)
    {
        _portfolio = portfolio;
        _portfolio.OnSummary += s => AvailableBalance = s.AvailableBalance;
        _portfolio.OnUpdate  += s => AvailableBalance = s.AvailableBalance;
    }

    public Task StartAsync() => _portfolio.ConnectAsync();
}
```

## Active orders and trades

Wire both channels together for a complete trading loop:

```csharp theme={null}
var orders = serviceProvider.GetRequiredService<STXActiveOrdersChannel>();
var trades = serviceProvider.GetRequiredService<STXActiveTradesChannel>();

orders.OnOrderUpdate += o =>
    _logger.LogInformation("Order {Id} -> {Status}", o.Id, o.Status);

trades.OnTrade += t =>
    _logger.LogInformation("Fill {TradeId}: {MarketId} {Price}c x {Quantity}",
        t.Id, t.MarketId, t.Price, t.Quantity);

await orders.ConnectAsync();
await trades.ConnectAsync();
```

<Note>
  Both channels require an authenticated session. The JWT is pulled from `STXUserStorage` automatically — call `LoginAsync` before `ConnectAsync`.
</Note>

## Market channel (price ticks)

Subscribe to specific market IDs to receive live bid/ask updates and market state changes:

```csharp theme={null}
var market = serviceProvider.GetRequiredService<STXMarketChannel>();

market.OnPriceUpdate += tick =>
{
    // tick carries: MarketId, BestBid, BestAsk, LastTrade, MarketStatus, ...
    Console.WriteLine($"{tick.MarketId}  bid={tick.BestBid}  ask={tick.BestAsk}");
};

await market.ConnectAsync();
await market.SubscribeAsync("mkt_abc", "mkt_def");
```

You can subscribe and unsubscribe at runtime as your market universe changes. The channel deduplicates subscriptions and only sends the delta to the server.

## Full startup sequence

The `BackgroundService` pattern from `cssdk-console` shows the recommended order for connecting all channels at startup and cleanly disconnecting on shutdown:

```csharp theme={null}
public class STXWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stop)
    {
        await _login.LoginAsync(email, password, keepSessionAlive: true);

        await _portfolio.ConnectAsync();
        await _orders.ConnectAsync();
        await _trades.ConnectAsync();
        await _market.ConnectAsync();

        stop.WaitHandle.WaitOne();   // block until the host shuts down

        await _market.DisconnectAsync();
        await _trades.DisconnectAsync();
        await _orders.DisconnectAsync();
        await _portfolio.DisconnectAsync();
    }
}
```

## Reconnection behavior

When the underlying socket drops, the SDK:

<Steps>
  <Step title="Retries with exponential backoff">
    Reconnect attempts start at 250 ms and cap at 5 s.
  </Step>

  <Step title="Rejoins all topics">
    Every previously-joined topic is rejoined automatically on reconnect.
  </Step>

  <Step title="Preserves event handlers">
    Your registered callbacks stay bound — no re-registration is needed.
  </Step>
</Steps>

<Tip>
  If the session JWT expired during the outage and you started with `keepSessionAlive: true`, `STXSessionBackgroundService` refreshes the token before the next connect attempt.
</Tip>

## See also

* [Authentication](/sdks/csharp/authentication) — why `keepSessionAlive` matters for long-running channel connections
* [Trading](/sdks/csharp/trading) — using `STXActiveOrdersChannel` with `cancelOnDisconnect`
* [Settlements](/sdks/csharp/settlements) — `STXActiveSettlementsChannelWrapper` for live settlement events
