> For the complete documentation index, see [llms.txt](https://docs.aquanow.io/cams/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aquanow.io/cams/market-data/websocket.md).

# Websocket

### Websocket Endpoints

#### Environments

There are two environments to access our websocket market data feeds:

1. **Live**

<pre><code><strong>wss://marketdata.aquanow.com/ 
</strong></code></pre>

2. **Sandbox**

```
wss://marketdata.staging.aquanow.com/
```

### Websocket Access and Authorization

API Authentication is done using an OAuth2.0. User needs to associate the following information in the payload of the subscription message. View the [Authorization](/cams/security/oauth2.0.md) page for more detail.

#### Subscribe

In order to receive data feed, users sends a *subscribe* message to the server, after successful websocket connection. Users must also indicate the channel they wish to subscribe on in the subscription request.

\
When a subscribe message is received with a pair and channel, the server will respond with a **subscription** message that lists all channels you are subscribed to.

#### There are three channels you can subscribe for:

1. `orderBook` - Orderbook across various marketplaces and exchanges.
2. `ticker` - Open, High, Low, Close for a ticker, every minute published
3. `gbbo` - Real time best price/bids updates for subscribed ticker
4. `priceStatistics`  - 24 hour statistics for High, Low, % change in price and notional change for a pair over websocket channel. It is published every minute

**Note:** that the Subscribe request **MUST** be a JSON string. For example, in Javascript this can be achieved by using the `JSON.stringify` method.

#### Request Parameters

{% tabs %}
{% tab title="orderBook" %}

|       Name      |  Type  | Description                                                          | Required |
| :-------------: | :----: | -------------------------------------------------------------------- | -------- |
| `authorization` | String | Access token for OAuth authentication                                | Yes      |
|    `channel`    | String | Channel of subscription: orderBook                                   | Yes      |
|      `type`     | String | Type of action; subscribe or unsubscribe                             | Yes      |
|     `nonce`     | String | Numeric string timestamp in milliseconds of when the request is sent | Yes      |
|    `username`   | String | Username of a client in Aquanow System                               | Yes      |
|      `pair`     | String | Symbol/currency pair; ex. – pair: “BTC-USD”                          | Yes      |
|     `depth`     | Number | Depth of an orderbook; ex. – depth: 5                                | No       |
|   `precision`   | Number | <p>Precision level;<br>ex. - precision: 2</p>                        | No       |
|   {% endtab %}  |        |                                                                      |          |

{% tab title="ticker" %}

|       Name      |  Type  | Description                                                          | Required |
| :-------------: | :----: | -------------------------------------------------------------------- | -------- |
| `authorization` | String | Access token for Oauth authentication                                | Yes      |
|    `channel`    | String | Channel of subscription. Ex - "gbbo"                                 | Yes      |
|      `type`     | String | Type of action; subscribe or unsubscribe                             | Yes      |
|     `nonce`     | String | Numeric string timestamp in milliseconds of when the request is sent | Yes      |
|      `pair`     | String | Symbol/currency pair; ex. – pair: “BTC-CAD”                          | Yes      |
|    `username`   | String | Username of a client in Aquanow System                               | Yes      |
|   {% endtab %}  |        |                                                                      |          |

{% tab title="gbbo" %}

|       Name      |  Type  | Description                                                          | Required |
| :-------------: | :----: | -------------------------------------------------------------------- | -------- |
| `authorization` | String | Access token for Oauth authentication                                | Yes      |
|    `channel`    | String | Channel of subscription. Ex - "ticker"                               | Yes      |
|      `type`     | String | Type of action; subscribe or unsubscribe                             | Yes      |
|     `nonce`     | String | Numeric string timestamp in milliseconds of when the request is sent | Yes      |
|      `pair`     | String | Symbol/currency pair; ex. – pair: “BTC-CAD”                          | Yes      |
|    `username`   | String | Username of a client in Aquanow System                               | Yes      |
|   {% endtab %}  |        |                                                                      |          |

{% tab title="priceStatistics" %}

|       Name      |  Type  | Description                                                          | Required |
| :-------------: | :----: | -------------------------------------------------------------------- | -------- |
| `authorization` | String | Access token for Oauth authentication                                | Yes      |
|    `channel`    | String | Channel of subscription. Ex - "ticker"                               | Yes      |
|      `type`     | String | Type of action; subscribe or unsubscribe                             | Yes      |
|     `nonce`     | String | Numeric string timestamp in milliseconds of when the request is sent | Yes      |
|      `pair`     | String | Symbol/currency pair; ex. – pair: “BTC-CAD”                          | Yes      |
|    `username`   | String | Username of a client in Aquanow System                               | Yes      |
|   {% endtab %}  |        |                                                                      |          |
|  {% endtabs %}  |        |                                                                      |          |

#### Unsubscribe

You can unsubscribe from a channel at any time.

Example Request

{% tabs %}
{% tab title="Javascript" %}

```javascript
JSON.stringify({
  "type": "unsubscribe",      // Message Type
  "channel": 'orderBook',     // Subscription Channel
  "pair": 'BTC-USD'           // Symbol
})
```

{% endtab %}
{% endtabs %}

### Example Usage

{% tabs %}
{% tab title="orderBook" %}

```javascript
import axios from 'axios';
import qs from 'qs';
import WebSocket from 'ws';

const address = "wss://marketdata.aquanow.com";

const ws = new WebSocket(address);
const clientId = '';
const clientSecret = '';
const tokenEndpoint = `https://auth.cert.aquanow.com/oauth2/token`;
const scope = 'marketdata/read';

async function getAccessToken() {
  const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const data = qs.stringify({
    grant_type: 'client_credentials',
    scope: scope,
  });

  try {
    const response = await axios.post(tokenEndpoint, data, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: `Basic ${authString}`,
      },
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error obtaining access token:', error.response.data);
  }
}

async function subscribeToOrders() {
  const authorization = await getAccessToken();
  const timestamp = Date.now();
  const subsOption = JSON.stringify({
    type: 'subscribe',
    channel: 'orderBook',
    authorization: 'Bearer XXXXXXXX',
    username: 'testAccount',
    pair: 'BTC-USD',
    nonce: timestamp,
    depth: 5
  });

  ws.send(subsOption);
}

ws.on('open', () => {
  console.log(`WS tunnel opened - trade`);
  subscribeToOrders();
});

ws.on('message', (data) => {
  console.log('data', JSON.parse(data));
});
```

{% endtab %}

{% tab title="ticker" %}

```javascript
import axios from 'axios';
import qs from 'qs';
import WebSocket from 'ws';

const address = "wss://marketdata.aquanow.com";

const ws = new WebSocket(address);
const clientId = '';
const clientSecret = '';
const tokenEndpoint = `https://auth.cert.aquanow.com/oauth2/token`;
const scope = 'marketdata/read';

async function getAccessToken() {
  const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const data = qs.stringify({
    grant_type: 'client_credentials',
    scope: scope,
  });

  try {
    const response = await axios.post(tokenEndpoint, data, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: `Basic ${authString}`,
      },
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error obtaining access token:', error.response.data);
  }
}

async function subscribeToOrders() {
  const authorization = await getAccessToken();
  const timestamp = Date.now();
  const subsOption = JSON.stringify({
    type: 'subscribe',
    channel: 'gbbo',
    authorization: 'Bearer XXXXXXXX',
    username: 'testAccount',
    pair: 'BTC-USD',
    nonce: timestamp,
  });

  ws.send(subsOption);
}

ws.on('open', () => {
  console.log(`WS tunnel opened - trade`);
  subscribeToOrders();
});

ws.on('message', (data) => {
  console.log('data', JSON.parse(data));
});
```

{% endtab %}

{% tab title="gbbo" %}

```javascript
import axios from 'axios';
import qs from 'qs';
import WebSocket from 'ws';

const address = "wss://marketdata.aquanow.com";

const ws = new WebSocket(address);
const clientId = '';
const clientSecret = '';
const tokenEndpoint = `https://auth.cert.aquanow.com/oauth2/token`;
const scope = 'marketdata/read';

async function getAccessToken() {
  const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const data = qs.stringify({
    grant_type: 'client_credentials',
    scope: scope,
  });

  try {
    const response = await axios.post(tokenEndpoint, data, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: `Basic ${authString}`,
      },
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error obtaining access token:', error.response.data);
  }
}

async function subscribeToOrders() {
  const authorization = await getAccessToken();
  const timestamp = Date.now();
  const subsOption = JSON.stringify({
    type: 'subscribe',
    channel: 'gbbo',
    authorization: 'Bearer XXXXXXXX',
    username: 'testAccount',
    pair: 'BTC-USD',
    nonce: timestamp,
  });

  ws.send(subsOption);
}

ws.on('open', () => {
  console.log(`WS tunnel opened - trade`);
  subscribeToOrders();
});

ws.on('message', (data) => {
  console.log('data', JSON.parse(data));
});
```

{% endtab %}

{% tab title="priceStatistics" %}

```javascript
import axios from 'axios';
import qs from 'qs';
import WebSocket from 'ws';

const address = "wss://marketdata.aquanow.com";

const ws = new WebSocket(address);
const clientId = '';
const clientSecret = '';
const tokenEndpoint = `https://auth.cert.aquanow.com/oauth2/token`;
const scope = 'marketdata/read';

async function getAccessToken() {
  const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
  const data = qs.stringify({
    grant_type: 'client_credentials',
    scope: scope,
  });

  try {
    const response = await axios.post(tokenEndpoint, data, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: `Basic ${authString}`,
      },
    });

    return response.data.access_token;
  } catch (error) {
    console.error('Error obtaining access token:', error.response.data);
  }
}

async function subscribeToOrders() {
  const authorization = await getAccessToken();
  const timestamp = Date.now();
  const subsOption = JSON.stringify({
    type: 'subscribe',
    channel: 'priceStatistics',
    authorization: 'Bearer XXXXXXXX',
    username: 'testAccount',
    pair: 'BTC-USD',
    nonce: timestamp,
  });

  ws.send(subsOption);
}

ws.on('open', () => {
  console.log(`WS tunnel opened - trade`);
  subscribeToOrders();
});

ws.on('message', (data) => {
  console.log('data', JSON.parse(data));
});
```

{% endtab %}
{% endtabs %}

#### Example Responses

{% tabs %}
{% tab title="orderBook" %}

```json
{
  dataType: 'aggOB',
  lastUpdated: 1726790944059,
  symbol: 'BTC-USD',
  precision: [ -1, 0, 1, 2 ],
  bids: [
    { quote: 62708.59, quantity: 0.1, cumulativeQuantity: 0.1 },
    { quote: 62707.84, quantity: 0.2, cumulativeQuantity: 0.3 },
    { quote: 62707.39, quantity: 0.1, cumulativeQuantity: 0.4 },
    { quote: 62707.04, quantity: 0.3, cumulativeQuantity: 0.7 },
    { quote: 62706.84, quantity: 0.1, cumulativeQuantity: 0.8 }
  ],
  asks: [
    { quote: 63025.77, quantity: 0.1, cumulativeQuantity: 0.1 },
    { quote: 63026.65, quantity: 0.1, cumulativeQuantity: 0.2 },
    { quote: 63026.66, quantity: 0.1, cumulativeQuantity: 0.3 },
    { quote: 63028.97, quantity: 4, cumulativeQuantity: 4.3 },
    { quote: 63029.02, quantity: 0.1, cumulativeQuantity: 4.4 }
  ]
}
```

{% endtab %}

{% tab title="ticker" %}

```json
 {
  symbol: 'BTC-USD',
  exchange: 'Aqua',
  open: 62885,
  close: 62878.395,
  high: 62878.395,
  low: 62878.395,
  itemDateTime: 1726790880054
}
```

{% endtab %}

{% tab title="gbbo" %}

```json
{
  dataType: 'aggBBO',
  lastUpdated: 1726790834054,
  symbol: 'BTC-USD',
  precisions: [ -1, 0, 1, 2 ],
  bestBid: 62717.82,
  bestAsk: 63032.68,
  spread: 314.86
}

```

{% endtab %}

{% tab title="priceStatistics" %}

```json
{
  symbol: 'BTC-USD',
  itemDateTime: 1726790940000,
  high: 63871.645,
  low: 61585.59,
  percentChange: 1.4470937791356022,
  notionalChange: 897.12
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.aquanow.io/cams/market-data/websocket.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
