# Live quotes

> Stream quotes over a WebSocket that update whenever pools change.

This page is part of the DEX Aggregator docs. The aggregator is at `https://router.intear.tech`, with live quotes at `wss://router.intear.tech/route/subscribe`, on NEAR mainnet only. https://docs.intear.tech/dex-aggregator/llms-full.txt has all of its pages in one file, and https://docs.intear.tech/llms.txt lists every page of the Intear docs.

When a user is looking at a swap form, the quote gets old fast. Instead of polling `/route`, open a WebSocket to `/route/subscribe`. The server sends a new set of quotes every time the pools change in a way that changes the result.

```
wss://router.intear.tech/route/subscribe
```

## How it works

1. Open the socket.

2. Send a request. `query` is the same query string `/route` takes, and `id` is any non-negative integer you choose:

   ```json
   {
     "id": 1,
     "query": "token_in=near&token_out=nep141:usdt.tether-token.near&amount_in=1000000000000000000000000&slippage_type=Fixed&slippage=0.01&trader_account_id=alice.near"
   }
   ```

3. Receive quotes. The first update comes once routing is done, then a new one whenever the quotes change:

   ```json
   { "id": 1, "routes": [ ... ] }
   ```

   `routes` is the same array of quotes `/route` returns, empty if no DEX found a route.

4. When the user changes the form, send a new request with a new `id`. It replaces the previous one: the server stops updating the old request. Updates of the old request that were already on their way may still arrive, so ignore any update whose `id` isn't the latest one you sent.

5. To stop updates without closing the socket, send a message with only an `id`:

   ```json
   { "id": 2 }
   ```

## Example

**JavaScript**

```js
const socket = new WebSocket('wss://router.intear.tech/route/subscribe');
let latestId = 0;

function requestQuotes(params) {
  latestId += 1;
  socket.send(JSON.stringify({ id: latestId, query: new URLSearchParams(params).toString() }));
}

socket.addEventListener('message', (event) => {
  const update = JSON.parse(event.data);
  if (update.id !== latestId) return; // an update of an older request
  if ('error' in update) {
    showError(update.error);
  } else {
    showQuotes(update.routes);
  }
});

socket.addEventListener('open', () => {
  requestQuotes({
    token_in: 'near',
    token_out: 'nep141:usdt.tether-token.near',
    amount_in: '1000000000000000000000000',
    slippage_type: 'Fixed',
    slippage: '0.01',
    trader_account_id: 'alice.near',
  });
});
```

The whole file, tested in CI: https://docs.intear.tech/snippets/js/src/live-quotes.js

**Rust**

With [tokio-tungstenite](https://docs.rs/tokio-tungstenite), using the `Quote` type from the [Quickstart](https://docs.intear.tech/dex-aggregator/quickstart.md):

```toml title="Cargo.toml"
futures-util = "0.3"
serde_json = "1"
tokio-tungstenite = { version = "0.30", features = ["native-tls"] }
```

The whole file, tested in CI: https://docs.intear.tech/snippets/rust/Cargo.toml

```rust
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[derive(Deserialize)]
#[serde(untagged)]
enum Update {
    Routes { id: u64, routes: Vec<Quote> },
    Error { id: u64, error: String },
}

let (mut socket, _) = connect_async("wss://router.intear.tech/route/subscribe").await?;

let latest_id = 1;
let query = "token_in=near&token_out=nep141:usdt.tether-token.near&amount_in=1000000000000000000000000\
    &slippage_type=Fixed&slippage=0.01&trader_account_id=alice.near";
let request = serde_json::json!({ "id": latest_id, "query": query });
socket.send(Message::text(request.to_string())).await?;

while let Some(message) = socket.next().await {
    let Message::Text(text) = message? else {
        continue;
    };
    match serde_json::from_str::<Update>(&text)? {
        Update::Routes { id, routes } if id == latest_id => show_quotes(routes),
        Update::Error { id, error } if id == latest_id => show_error(error),
        _ => {} // an update of an older request
    }
}
```

The whole file, tested in CI: https://docs.intear.tech/snippets/rust/src/lib.rs

## Things to know

- **Errors don't close the socket.** An invalid query returns `{ "id": 1, "error": "..." }` and the socket stays open.
- **Invalid messages close the socket.** A message that isn't JSON with a non-negative integer `id` and an optional string `query` ends the connection, without a close frame.
- **Updates are only sent on changes.** If quotes stay the same, nothing is sent.
