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

# WS/API Best Practices

> Use Phoenix REST, WebSocket, and RPC surfaces without drifting state or hitting rate limits.

Use REST for snapshots, historical reads, and server-built transaction workflows. Use WebSockets for live exchange, market, orderbook, and trader-state updates. Use Solana RPC for blockhashes, simulation, transaction submission, confirmation, and custom account reads.

## Default Pattern

1. Fetch startup snapshots over REST.
2. Start WebSocket subscriptions for exchange metadata, market stats, orderbooks, and trader state.
3. Apply snapshots and deltas through SDK primitives.
4. Build instructions from the exchange cache.
5. Sign and send through the user's wallet or signer service.
6. Reconcile from trader-state streams; refetch REST snapshots after reconnects or sequence gaps.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { createPhoenixClient, createTraderStateStore } from "@ellipsis-labs/rise";

  const client = createPhoenixClient({
    apiUrl: "https://perp-api.phoenix.trade",
    rpcUrl: "https://api.mainnet-beta.solana.com",
    ws: { connectMode: "eager" },
    exchangeMetadata: { stream: true },
  });

  await client.exchange.ready();

  const traderState = createTraderStateStore(client);
  const trader = traderState.resource({
    authority: "AUTHORITY_PUBKEY",
    traderPdaIndex: 0,
  });

  const release = trader.retain();
  await trader.ready();
  ```

  ```rust Rust theme={null}
  use phoenix_rise::api::{PhoenixHttpClient, PhoenixMetadata, PhoenixWSClient, Trader, TraderKey};
  use solana_pubkey::Pubkey;

  let http = PhoenixHttpClient::new_from_env()?;
  let exchange = http.get_exchange().await?.into();
  let mut metadata = PhoenixMetadata::new(exchange);

  let authority: Pubkey = "AUTHORITY_PUBKEY".parse()?;
  let trader_key = TraderKey::from_authority(authority);
  let mut trader = Trader::new(trader_key.clone());

  let ws = PhoenixWSClient::new_from_env()?;
  let (mut trader_rx, _handle) = ws.subscribe_to_trader_state(&authority)?;
  ```
</CodeGroup>

## Rate Limits

Most public market and trader reads do not require auth, but authenticated sessions receive higher API limits. Auth is required for referral-code onboarding and notifications.

To avoid rate-limit pressure:

* Prefer WebSocket streams for frequently changing state.
* Share one process-level Phoenix client where possible.
* Share one subscription per market or trader and fan out locally.
* Cache exchange params with `client.exchange` or `PhoenixMetadata`.
* Cache trader state with `createTraderStateStore(client)` or `Trader::apply_update(...)`.
* Use REST polling for slow reconciliation, not frame-by-frame UI updates.
* Back off on `429` responses and retry after the server-provided delay when available.

## Snapshots And Deltas

Do not hand-roll snapshot/delta application unless you are building SDK internals.

In TypeScript:

* `client.exchange` bootstraps from API or RPC, applies exchange WebSocket snapshots and deltas, and emits cache events.
* `createTraderStateStore(client)` applies trader-state snapshots and deltas and exposes derived positions, orders, triggers, history, and `marginInputs()`.
* `client.marketData()` combines all-mids, market-stats, and mark-price streams into per-symbol rows.

In Rust:

* `PhoenixMetadata::new(exchange)` creates the exchange cache from an HTTP snapshot.
* `metadata.apply_market_stats(&stats)` updates market mark-price inputs used by margin math.
* `Trader::apply_update(&msg)` applies trader-state WebSocket updates to a local trader container.
* `L2Book::apply_update(&msg)` maintains an orderbook container.

## Reconnects

WebSocket clients can reconnect, but your application still needs a reconciliation policy. After a reconnect, sequence gap, or prolonged disconnect:

* Refresh exchange metadata over REST or wait for a fresh exchange snapshot.
* Refetch or await a fresh trader-state snapshot before showing account health as final.
* Drop stale L2 book state unless the SDK resource confirms it has been resynced.
* Recompute margin only after both trader state and market prices are current.

## Notifications

Notifications are an authenticated workflow. Use a Phoenix auth session when subscribing to user-specific notifications over REST or WebSocket. Public market streams should stay unauthenticated unless your integration needs authenticated API limits for the rest of its traffic.

References:

* [Auth](/sdk/auth)
* [Exchange Data](/sdk/markets)
* [Accounts](/sdk/accounts)
* [Orders](/sdk/orders)
* [Margin](/sdk/margin)
* [WebSocket API](/api/websocket)
* [TypeScript WebSocket example](https://github.com/Ellipsis-Labs/rise-public/blob/master/ts/examples/phoenix-ws-example.ts)
* [Rust market-stats example](https://github.com/Ellipsis-Labs/rise-public/blob/master/rust/sdk/examples/subscribe_market_stats.rs)
