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

# WebSocket

> Real-time quote streaming via WebSocket

## Overview

The SDK provides WebSocket support for real-time quote streaming. The WebSocket client handles connection management, automatic reconnection with exponential backoff, and ping/pong keep-alive.

There are two ways to use WebSocket:

1. **High-level**: Use `streamQuotes` / `streamQuotesByTicker` convenience methods on `MakerClient`
2. **Low-level**: Use `WSClient` directly with event-based message handling

## Enabling WebSocket

Before streaming quotes, enable the WebSocket connection:

<CodeGroup>
  ```typescript TypeScript theme={null}
  const ws = client.maker.enableWebSocket('wss://api.signet.kaleidoswap.com/ws/my-client-id');
  ```

  ```python Python theme={null}
  ws = client.maker.enable_websocket("wss://api.signet.kaleidoswap.com/ws/my-client-id")
  ```
</CodeGroup>

The URL includes a client ID for session tracking. The `enableWebSocket` method returns a `WSClient` instance.

## High-Level API

### `streamQuotesByTicker` / `stream_quotes_by_ticker`

The simplest way to stream quotes. Automatically discovers routes and starts streaming.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const unsubscribe = await client.maker.streamQuotesByTicker(
    'BTC',           // fromTicker
    'USDT',          // toTicker
    100000,          // amount
    (quote) => {     // callback
      console.log(`Price: ${quote.price}, RFQ: ${quote.rfq_id}`);
    },
    {                // options (optional)
      preferredFromLayer: 'BTC_LN',
      preferredToLayer: 'RGB_LN'
    }
  );

  // Stop streaming when done
  unsubscribe();
  ```

  ```python Python theme={null}
  from kaleido_sdk import Layer

  unsubscribe = await client.maker.stream_quotes_by_ticker(
      from_ticker="BTC",
      to_ticker="USDT",
      amount=100000,
      on_update=lambda quote: print(f"Price: {quote.price}, RFQ: {quote.rfq_id}"),
      preferred_from_layer=Layer.btc_ln,
      preferred_to_layer=Layer.rgb_ln
  )

  # Stop streaming when done
  unsubscribe()
  ```
</CodeGroup>

### `streamQuotes` / `stream_quotes`

Stream quotes for a specific route (asset IDs and layers).

<CodeGroup>
  ```typescript TypeScript theme={null}
  const unsubscribe = await client.maker.streamQuotes(
    'BTC',           // from_asset ID
    'USDT',          // to_asset ID
    100000,          // from_amount (or null)
    'BTC_LN',        // from_layer (or null)
    'RGB_LN',        // to_layer (or null)
    (quote) => {
      console.log(`${quote.from_amount} -> ${quote.to_amount}`);
    }
  );
  ```

  ```python Python theme={null}
  unsubscribe = await client.maker.stream_quotes(
      from_asset="BTC",
      to_asset="USDT",
      from_amount=100000,
      from_layer=Layer.btc_ln,
      to_layer=Layer.rgb_ln,
      on_update=lambda quote: print(f"{quote.from_amount} -> {quote.to_amount}")
  )
  ```
</CodeGroup>

### `streamQuotesForAllRoutes` / `stream_quotes_for_all_routes`

Stream quotes for all available routes between two tickers simultaneously.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const unsubscribers = await client.maker.streamQuotesForAllRoutes(
    'BTC', 'USDT', 100000,
    (route, quote) => {
      console.log(`Route ${route}: price=${quote.price}`);
    }
  );
  // Returns: Map<string, () => void>
  // Call each unsubscriber to stop, or iterate and call all
  ```

  ```python Python theme={null}
  unsubscribers = await client.maker.stream_quotes_for_all_routes(
      from_ticker="BTC",
      to_ticker="USDT",
      amount=100000,
      on_update=lambda route, quote: print(f"Route {route}: price={quote.price}")
  )
  # Returns: dict[str, Callable]
  ```
</CodeGroup>

### `getAvailableRoutes` / `get_available_routes`

Discover available routes for a pair before streaming.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const routes = await client.maker.getAvailableRoutes('BTC', 'USDT');
  // Returns: Array<{ from_layer: string; to_layer: string }>
  for (const route of routes) {
    console.log(`${route.from_layer} -> ${route.to_layer}`);
  }
  ```

  ```python Python theme={null}
  routes = await client.maker.get_available_routes("BTC", "USDT")
  for route in routes:
      print(f"{route['from_layer']} -> {route['to_layer']}")
  ```
</CodeGroup>

## Low-Level WSClient API

For full control, use the `WSClient` directly.

### Connection

<CodeGroup>
  ```typescript TypeScript theme={null}
  const ws = client.maker.enableWebSocket('wss://api.signet.kaleidoswap.com/ws/my-client');

  await ws.connect();
  console.log(`Connected: ${ws.isConnected()}`);

  // When done
  ws.disconnect();
  ```

  ```python Python theme={null}
  ws = client.maker.enable_websocket("wss://api.signet.kaleidoswap.com/ws/my-client")

  await ws.connect()
  print(f"Connected: {ws.is_connected()}")

  # When done
  ws.disconnect()
  ```
</CodeGroup>

### Events

Subscribe to events using `on` / `off`:

| Event                                              | Data              | Description                       |
| -------------------------------------------------- | ----------------- | --------------------------------- |
| `connected`                                        | --                | Connection established            |
| `disconnected`                                     | --                | Connection closed                 |
| `reconnecting`                                     | `attempt: number` | Attempting reconnection           |
| `quoteResponse` / `quote_response`                 | `QuoteResponse`   | New quote received                |
| `connectionEstablished` / `connection_established` | connection data   | Server confirmed connection       |
| `pong`                                             | `PongResponse`    | Pong received                     |
| `error`                                            | `Error`           | An error occurred                 |
| `maxReconnectExceeded` / `max_reconnect_exceeded`  | --                | Max reconnection attempts reached |

<CodeGroup>
  ```typescript TypeScript theme={null}
  ws.on('connected', () => console.log('Connected'));
  ws.on('disconnected', () => console.log('Disconnected'));
  ws.on('reconnecting', (attempt) => console.log(`Reconnecting: attempt ${attempt}`));
  ws.on('quoteResponse', (quote) => console.log(`Quote: ${quote.price}`));
  ws.on('error', (error) => console.error(`Error: ${error.message}`));
  ws.on('maxReconnectExceeded', () => console.log('Max reconnects exceeded'));

  // Unsubscribe
  const handler = (quote) => { /* ... */ };
  ws.on('quoteResponse', handler);
  ws.off('quoteResponse', handler);
  ```

  ```python Python theme={null}
  ws.on("connected", lambda: print("Connected"))
  ws.on("disconnected", lambda: print("Disconnected"))
  ws.on("reconnecting", lambda attempt: print(f"Reconnecting: attempt {attempt}"))
  ws.on("quote_response", lambda quote: print(f"Quote: {quote['price']}"))
  ws.on("error", lambda err: print(f"Error: {err}"))
  ws.on("max_reconnect_exceeded", lambda: print("Max reconnects exceeded"))

  # Unsubscribe
  handler = lambda quote: ...
  ws.on("quote_response", handler)
  ws.off("quote_response", handler)
  ```
</CodeGroup>

### Requesting Quotes

<CodeGroup>
  ```typescript TypeScript theme={null}
  ws.requestQuote({
    from_asset: 'BTC',
    to_asset: 'USDT',
    from_amount: 100000,
    from_layer: 'BTC_LN',
    to_layer: 'RGB_LN'
  });
  ```

  ```python Python theme={null}
  ws.request_quote({
      "from_asset": "BTC",
      "to_asset": "USDT",
      "from_amount": 100000,
      "from_layer": "BTC_LN",
      "to_layer": "RGB_LN"
  })
  ```
</CodeGroup>

### Ping / Keep-Alive

The WSClient automatically pings the server at the configured interval. You can also ping manually:

<CodeGroup>
  ```typescript TypeScript theme={null}
  ws.ping();
  ```

  ```python Python theme={null}
  ws.ping()
  ```
</CodeGroup>

## Configuration

The WSClient accepts configuration options:

| Option                                            | Default             | Description                                            |
| ------------------------------------------------- | ------------------- | ------------------------------------------------------ |
| `maxReconnectAttempts` / `max_reconnect_attempts` | `5`                 | Maximum reconnection attempts                          |
| `reconnectDelay` / `reconnect_delay`              | `1000ms` / `1.0s`   | Base delay between reconnections (exponential backoff) |
| `pingInterval` / `ping_interval`                  | `30000ms` / `30.0s` | Interval between keep-alive pings                      |

Reconnection uses exponential backoff: `delay * 2^attempt`.

## WebSocket Protocol

The WebSocket uses a JSON message protocol:

### Message Types

| Action                   | Direction        | Description           |
| ------------------------ | ---------------- | --------------------- |
| `quote_request`          | Client -> Server | Request a price quote |
| `quote_response`         | Server -> Client | Quote update          |
| `ping`                   | Client -> Server | Keep-alive ping       |
| `pong`                   | Server -> Client | Keep-alive response   |
| `connection_established` | Server -> Client | Connection confirmed  |
| `error`                  | Server -> Client | Error message         |

### QuoteResponse Fields

| Field             | Type   | Description                                 |
| ----------------- | ------ | ------------------------------------------- |
| `from_asset`      | string | Source asset ID                             |
| `to_asset`        | string | Destination asset ID                        |
| `from_amount`     | number | Source amount                               |
| `to_amount`       | number | Destination amount                          |
| `price`           | number | Exchange rate                               |
| `rfq_id`          | string | Request-for-quote ID (use to create orders) |
| `price_precision` | number | Price decimal precision                     |
| `timestamp`       | number | Server timestamp                            |
| `expires_at`      | number | Quote expiry timestamp                      |
| `fee`             | Fee    | Fee breakdown                               |

## Best Practices

<AccordionGroup>
  <Accordion title="Handle disconnections gracefully">
    Subscribe to `disconnected` and `reconnecting` events. The WSClient automatically reconnects with exponential backoff, but you should handle the case where max attempts are exceeded.
  </Accordion>

  <Accordion title="Use the high-level API when possible">
    `streamQuotesByTicker` handles route discovery, connection management, and quote routing for you. Only use the low-level `WSClient` when you need custom control.
  </Accordion>

  <Accordion title="Unsubscribe when done">
    Always call the unsubscribe function returned by `streamQuotes` / `streamQuotesByTicker` when you no longer need quotes. This prevents memory leaks and unnecessary network traffic.
  </Accordion>

  <Accordion title="Use rfq_id from quotes to create orders">
    The `rfq_id` in each quote response is what you pass to `createSwapOrder`. Use the most recent quote to ensure the rate is still valid.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Examples" icon="file-code" href="/sdk/examples">
    See WebSocket streaming in complete end-to-end examples
  </Card>

  <Card title="Client Reference" icon="code" href="/sdk/api-reference">
    Full reference for all streaming methods on MakerClient
  </Card>

  <Card title="Types" icon="brackets-curly" href="/sdk/types">
    QuoteResponse, QuoteRequest, and other WebSocket type definitions
  </Card>

  <Card title="Best Practices" icon="star" href="/sdk/best-practices">
    Reconnection strategies and production patterns
  </Card>
</CardGroup>
