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

# Real-Time Orderbook

> Stream a live aggregated orderbook with the SDK, hooks, or UI components

The AGG WebSocket delivers a full aggregated orderbook snapshot on subscribe, then incremental
deltas as the book changes. Each outcome has its own orderbook — there is no complement derivation.
Each level includes per-venue attribution so you can render both the aggregated depth and the venue
breakdown from the same stream.

<Warning>
  **Orderbook subscriptions are keyed by `venueMarketOutcomeId`** — the `outcomes[].id` on REST
  market responses — not by `venueMarketId`. Subscribing with a `venueMarketId` never resolves a
  book and the gateway replies with a `Snapshot unavailable` error. (Only the REST
  `GET /orderbooks` endpoint and the arb streams use market-level ids.)
</Warning>

<Tabs>
  <Tab title="SDK (vanilla JS/TS)">
    Full control over the WebSocket connection and local orderbook state.

    ## 1. Connect and subscribe

    ```typescript theme={null}
    import { createAggClient } from "@agg-build/sdk";

    const client = createAggClient({
      baseUrl: "https://api.agg.market",
      appId: "your-app-id",
      wsUrl: "wss://ws.agg.market/ws",
    });

    let book = null;

    const ws = client.createWebSocket({
      onSnapshot: (_outcomeId, nextBook) => {
        book = nextBook;
        renderOrderbook(book);
      },
      onDelta: (_outcomeId, nextBook) => {
        book = nextBook;
        renderOrderbook(book);
      },
      onError: (msg) => {
        console.error(msg.message);
      },
    });

    ws.subscribe("your-outcome-id", "orderbook");
    ```

    The SDK applies snapshots and deltas for you, tracks `seq`, validates `checksum` (XOR of
    per-level CRC32), drops stale deltas where `seq <= current.seq`, and requests a fresh snapshot
    when integrity checks fail. The gateway is a stateless fan-out — all orderbook recovery is
    handled client-side by the SDK.

    ## 2. Read the orderbook

    The `OrderbookState` passed to callbacks uses object-shaped levels:

    ```typescript theme={null}
    interface OrderbookState {
      outcomeId: string;
      bids: Array<{ price: number; size: number; venues: Record<string, number> }>;
      asks: Array<{ price: number; size: number; venues: Record<string, number> }>;
      venueOrderbooks: Record<
        string,
        {
          bids: Array<{ price: number; size: number }>;
          asks: Array<{ price: number; size: number }>;
        }
      >;
      venues: Record<string, { bestBid: number | null; bestAsk: number | null }>;
      midpoint: number | null;
      spread: number | null;
      seq: number;
      checksum: number;
      timestamp: number; // seconds
    }
    ```

    ## 3. Per-venue orderbooks

    Per-venue depth is available on the same object:

    ```typescript theme={null}
    const ws = client.createWebSocket({
      onSnapshot: (_outcomeId, book) => {
        console.log(book.venueOrderbooks.predict?.bids);
        console.log(book.venueOrderbooks.polymarket?.asks);
      },
    });
    ```

    ## 4. REST fallback

    For one-time fetches without a live socket:

    ```typescript theme={null}
    const response = await client.getOrderbooks({
      venueMarketIds: ["your-market-id"],
      depth: 20,
    });

    const book = response.data[0];
    if (book?.status !== "ok") {
      throw new Error(book?.error?.message ?? "No live orderbook available");
    }

    // book.venueOrderbooks — per-venue depth keyed by venue
    // book.matchedMarkets  — venue markets considered for the requested market
    // book.requestedMarket — lifecycle metadata for the requested market
    ```
  </Tab>

  <Tab title="Hooks (React)">
    <Note>
      See the [Setup Guide](/api/setup) for the one-time `AggProvider` and `QueryClientProvider`
      wiring. This recipe starts at the hook usage layer.
    </Note>

    ## 1. Live orderbook

    ```tsx theme={null}
    import { useLiveMarket } from "@agg-build/hooks";

    function Orderbook({ marketId }) {
      const { orderbook, isConnected, integrity } = useLiveMarket(marketId);

      if (!orderbook) return <div>Connecting...</div>;

      return (
        <div>
          <p>Connected: {String(isConnected)}</p>

          <h3>Bids</h3>
          {orderbook.bids.map((level) => (
            <div key={level.price}>
              {(level.price * 100).toFixed(0)}% — {level.size} contracts
              {" ("}
              {Object.entries(level.venues)
                .map(([venue, size]) => `${venue}: ${size}`)
                .join(", ")}
              {")"}
            </div>
          ))}

          <p>
            Midpoint: {orderbook.midpoint} | Spread: {orderbook.spread}
          </p>

          <h3>Asks</h3>
          {orderbook.asks.map((level) => (
            <div key={level.price}>
              {(level.price * 100).toFixed(0)}% — {level.size} contracts
            </div>
          ))}

          {integrity === "resyncing" && <p>Resyncing…</p>}
        </div>
      );
    }
    ```

    ## 2. Per-venue orderbooks

    ```tsx theme={null}
    import { useMarketOrderbook } from "@agg-build/hooks";

    function VenueOrderbooks({ venueMarketOutcomeId, venueOutcomes }) {
      const { data, isLoading } = useMarketOrderbook({
        venueMarketOutcomeId, // outcomes[].id — NOT a venueMarketId
        venueOutcomes, // [{ venue: "predict", venueMarketOutcomeId: "..." }, ...]
      });

      if (isLoading || !data) return <div>Loading...</div>;

      return (
        <div>
          {Object.entries(data.venueOrderbooks).map(([venue, book]) => (
            <div key={venue}>
              <h4>{venue}</h4>
              <p>Bids: {book.bids.length} levels</p>
              <p>Asks: {book.asks.length} levels</p>
            </div>
          ))}
        </div>
      );
    }
    ```

    ## 3. REST-only (no WebSocket)

    ```tsx theme={null}
    import { useAggClient } from "@agg-build/hooks";
    import { useQuery } from "@tanstack/react-query";

    function StaticOrderbook({ marketId }) {
      const client = useAggClient();
      const { data } = useQuery({
        queryKey: ["orderbooks", marketId],
        queryFn: () =>
          client.getOrderbooks({
            venueMarketIds: [marketId],
          }),
      });

      const book = data?.data[0];
      // book?.venueOrderbooks, book?.matchedMarkets, book?.requestedMarket
    }
    ```
  </Tab>

  <Tab title="UI Components">
    Drop-in React components for live orderbook depth, venue attribution, and chart/orderbook tabs.

    ## [Market Details](/components/events/market-details) card with orderbook tab

    ```tsx theme={null}
    import { MarketDetails } from "@agg-build/ui/events";

    function OrderbookCard({ event, marketId }) {
      return <MarketDetails event={event} marketId={marketId} defaultTab="order-book" />;
    }
    ```

    The card renders bid/ask rows, venue logos, sizes, totals, and live updates without manual
    subscription code.

    For a full event page with both chart and orderbook tabs, use
    [`EventMarketPage`](/components/pages/event-market-page) as shown in
    [Real-Time Charts](/recipes/websocket-charts).

    Browse the live [Market Details reference](/components/events/market-details) and
    [Event Market Page reference](/components/pages/event-market-page).
  </Tab>
</Tabs>

## Integrity

The SDK verifies `seq` and `checksum` automatically and requests a fresh snapshot when the local
book drifts. If you are implementing the wire protocol yourself, use the
[WebSocket Protocol](/api/websocket) page for the snapshot/delta formats and resnapshot flow.

## Related

<CardGroup cols={2}>
  <Card title="WebSocket Protocol" icon="gear" href="/api/websocket">
    Wire format, sequencing, resnapshot requests, and heartbeat behavior.
  </Card>

  <Card title="Real-Time Charts" icon="code" href="/recipes/websocket-charts">
    Build live candles from the same orderbook and trade streams.
  </Card>

  <Card title="User Notifications" icon="key" href="/recipes/websocket-notifications">
    Authenticated order and balance events on the same WebSocket connection.
  </Card>
</CardGroup>
