# Stream subscriptions

## Listen Key Mechanism

#### Description

The `listen_key` is a unique token required for user authentication and to establish a WebSocket connection. It binds a user to a WebSocket session, ensuring that only authenticated users can access the private streams.

#### Acquiring a Listen Key

* Users must first authenticate with the server to receive a `listen_key`
* This key is then used in the WebSocket connection headers to validate the user's session

#### Listen Key Expirations

* Listen keys have a limited lifetime of 60 minutes
* Users can prolong the key's lifetime
* The server monitors the listen's key expirations and will automatically close the WebSocket connection when they expire

***

## WebSocket Connection Query parameters documentation

#### listen\_key parameter

The `listen_key` parameter is crucial for accessing the WebSocket server. It carries the `listen_key` token that is unique to each user session.

#### **Obtaining the `listen_key`:**

* The `listen_key` can be obtained via a `GET` request to the `listen_key` endpoint provided by the server after user authentication.
* Once acquired, the `listen_key` must be included in the query parameter for the WebSocket handshake.

#### Signer parameter

The `signer` parameter identifies the main account associated with the WebSocket connection. This query parameter is used along with the `listen_key` to establish a secure and authenticated connection.

#### **Usage:**

* Key: `Signer`
* Value:  Address of the signer of trading account.&#x20;

***

## WebSocket Server Streams Documentation

### 1. Fills Stream (`fills_` prefix)

#### Description

* This is a private stream that provides real-time information about order fills.
* Requires authentication and authorization to access specific trading accounts.

#### Connection Request

To subscribe to the Fills Stream:

* **Action**: "subscribe"
* **Stream**: "fills\_{trading\_account\_address}"
  * Replace `{trading_account_address}` with the specific trading account you want to subscribe to.
* **ID**: A unique request identifier.

```json
{
  "action": "subscribe",
  "stream": "fills_{trading_account_address}",
  "id": "unique_request_id"
}
```

Example subscription request:

```json
{
  "action": "subscribe", "stream": "fills_0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f",
  "base": "ETH", "quote": "USDC", "ecosystem_book": true,
  "id": "5"
}
```

Example subscription response (same response structure as for HTTP requests

```
{ "result": "OK", "id": "5"}
```

#### Example Stream Events

Order flow:

submit -> if succ response -> put into processing queue ->:

* failed to process -> NOT\_PROCCESSED (matcher result = FAILED\_VALIDATION)
* processed -> ACK -> OPEN -> ...

{% hint style="info" %}
{% code overflow="wrap" %}
```markup
Existente of error_code_orderbook in event message indicates that actions was unsuccessfull  
```
{% endcode %}
{% endhint %}

#### Partially filled

{% code overflow="wrap" %}
```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "OK", // matching engine result
    "fill_price": "2716.2819", // avg fill price
    "fill_base_qty": "0.0007704", // fill qty in base
    "fill_quote_qty": "2.092623", // fill qty in quote
    "acc_base_qty": "0.0013676", // accumulated so far
    "acc_quote_qty": "3.714786", // accumulated so far
    "hash": "0x05fabffcde5a985b39a304803a501fe9d835e5762666592c2442e767fbc91798", // hash of the associated order
    "is_sell_side": false,
    "status": "PARTIALLY_FILLED"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```
{% endcode %}

#### Fully filled

```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "OK",
    "fill_price": "2802.823411",
    "fill_base_qty": "0.0011943",
    "fill_quote_qty": "3.347412",
    "acc_base_qty": "0.0011943",
    "acc_quote_qty": "3.347412",
    "hash": "0x054706cf2b72d614c864d6cad4a9a2634fae9901fd714bc71a0046a4afa8ea68",
    "is_sell_side": false,
    "status": "FILLED"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```

#### Failed validation

```json
example#1
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "FAILED_VALIDATION", <--- error description
    "fill_price": "0",
    "fill_base_qty": "0",
    "fill_quote_qty": "0",
    "acc_base_qty": "0",
    "acc_quote_qty": "0",
    "hash": "0x02e8e9fc7a892f225aa80d4e23f988da60daf35efe06886396a5ba70e610ede2",
    "is_sell_side": false,
    "status": "NOT_PROCESSED", <--- order status
    "error_code_orderbook": "FAILED_SIGN_CHECK" <--- new field
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```

```json
example#2
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "FAILED_VALIDATION",
    "fill_price": "0",
    "fill_base_qty": "0",
    "fill_quote_qty": "0",
    "acc_base_qty": "0",
    "acc_quote_qty": "0",
    "hash": "0x006bfc44272f61d09c54ddec5d648d114262b5520b5825c4be5d517afa7ba788",
    "is_sell_side": true,
    "status": "NOT_PROCESSED",
    "error_code_orderbook": "NOT_ENOUGH_BALANCE"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDT"
  }
}
```

#### Cancelled

```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "OK",
    "fill_price": "0",
    "fill_base_qty": "0",
    "fill_quote_qty": "0",
    "acc_base_qty": "0",
    "acc_quote_qty": "0",
    "hash": "0x07cec852aa9cfb6ed7007f793088e6a3c92f400e6299acf78060f916cfc95c67",
    "is_sell_side": true,
    "status": "CANCELLED"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```

#### Failed to cancel

{% code overflow="wrap" %}
```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "report_type": "CANCEL_ORDER",
    "req_hash": "0x0576635fb70c1d49bd11778c9c6d74fa7c0075667ca0f8b673e7199d5c105ce6", // hash of the request
    "entity_hash": "0x043b508c740f9912df5f5bab044087b79ce9e6f3ada48c2f2a3edd8496df50ca", // order hash intented to be cancelled
    "error_code_orderbook": "NO_ORDERS_WITH_THIS_ID"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580"
}
```
{% endcode %}

#### Matching engine unable to match remaining amount

```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "matcher_result": "SLIPPAGE",
    "fill_price": "0",
    "fill_base_qty": "0",
    "fill_quote_qty": "0",
    "acc_base_qty": "0",
    "acc_quote_qty": "0",
    "hash": "0x01d19066b73825550e387d6532736ceca2847193fe40ab2640a266d8751e6bb8",
    "is_sell_side": true,
    "status": "ACC"
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```

#### **Examples of special events:**

Cancel all order under specified ticker

{% code overflow="wrap" %}
```json
{
  "result": {
    "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
    "cancel_ticker_hash": "0x01d19066b73825550e387d6532736ceca2847193fe40ab2640a266d8751e6bb8", // hash of cancel all request
  },
  "stream": "fills",
  "client": "0x033e29bc9b537bae4e370559331e2bf35b434b566f41a64601b37f410f46a580",
  "pair": {
    "base": "AETH",
    "quote": "AUSDC"
  }
}
```
{% endcode %}

FAILED\_ROLLUP:

```json
{
    "result": {
        "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f",
        "fill_price": 2000, // fill price
        "fill_base_qty": 2, // fill qty in base asset that was failed
        "fill_quote_qty": 4000, // fill qty in quote asset that was failed
        "hash": "0x05fabffcde5a985b39a304803a501fe9d835e5762666592c2442e767fbc91798",
        "is_sell_side": false,
        "status": "FAILED_ROLLUP", // trade was failed due to some exceptional situation eg router taker
    },
    "stream": "fills",
    "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f"
    "pair": {
        "base": "AETH",
        "quote": "AUSDC"
     }
}
```

REIMBURSE:

```json
{
    "result": {
        "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f",
        "price": 0
        "fill_base_qty": "0.35", // reimburse amount in main gas token 
        "hash": "0x05fabffcde5a985b39a304803a501fe9d835e5762666592c2442e767fbc91798",
        "is_sell_side": false,
        "status": "REIMBURSE", // router trade was failed, so we incentivize market makers
    },
    "stream": "fills",
    "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f"
    "pair": {
        "base": "STRK", // always strk/strk
        "quote": "STRK"
     }
}
```

EXPIRED:

```json
{
    "result": {
        "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f",
        "fill_price": 1958, // fill price
        "pair": "ETH-USDC", # 
        "fill_base_qty": 2, // expired amount
        "fill_quote_qty": 3916, // expired amount 
        "hash": "0x05fabffcde5a985b39a304803a501fe9d835e5762666592c2442e767fbc91798",
        "is_sell_side": false,
        "status": "OK",
    },
    "stream": "fills",
    "client": "0x541cf2823e5d004e9a5278ef8b691b97382fd0c9a6b833a56131e12232a7f0f"
    "pair": {
        "base": "AETH",
        "quote": "AUSDC"
     }
}
```

### 2. Best Bid and Offer (BBO) Stream (`bbo`)

#### Description

* Provides real-time best bid and offer updates for a specified trading pair.

#### Connection Request

To subscribe to the BBO Stream:

* **Action**: "subscribe"
* **Stream**: "bbo"
* **Base**: The base token of the trading pair.
* **Quote**: The quote token of the trading pair.
* **Ecosystem\_book**: Boolean indicating whether to use Ecosystem Book updates.
* **ID**: A unique request identifier.

```json
{
  "action": "subscribe",
  "stream": "bbo",
  "base": "base_token",
  "quote": "quote_token",
  "ecosystem_book": true,
  "id": "unique_request_id"
}
```

Example subscription request:

```json
{
  "action": "subscribe", "stream": "bbo",
  "base": "ETH", "quote": "USDC", "ecosystem_book": true,
  "id": "5"
}
```

Example subscription response (same response structure as for HTTP requests)

```json
{ "result": "OK", "id": "5"}
```

Example Stream Event:

```json
{
    "result": {
        "bid": ["1958", "124.23", 2], // price and volume and num orders
        "ask": ["195", "87.11", 25],
        "time": 1705221916000 # epoch in millis
    },
    "stream": "bbo",
    "millis": 0,
    "ecosystem": true,
    "pair": {
        "base": "AETH",
        "quote": "AUSDC"
     }
}
```

### 3. Trade Stream (`trade`)

#### Description

* Real-time stream of trade data for a specified trading pair.

#### Connection Request

To subscribe to the Trade Stream:

* Use the same format as the BBO stream but with **Stream**: "trade".

```json
{
  "action": "subscribe",
  "stream": "trade",
  "base": "base_token",
  "quote": "quote_token",
  "ecosystem_book": true,
  "id": "unique_request_id"
}
```

Example subscription Request:

```json
{
  "action": "subscribe", "stream": "trade",
  "base": "ETH", "quote": "USDC", "ecosystem_book": true,
  "id": "5"
}
```

Example subscription Response (same response structure as for HTTP requests)

```json
{ "result": "OK", "id": "5"}
```

#### Example Stream Output

```json
{
    "result": {
        "price 1958, "base_qty": "2", "quote_qty":"3916", "is_sell_side": true,
        "time": 1705221916000 # epoch in millis
    },
    "stream": "trade",
    "millis": 0,
    "ecosystem": true,
    "pair": {
        "base": "AETH",
        "quote": "AUSDC"
     }
}
```

### 4. Snapshot Stream (`snap`)

#### Description

* Provides snapshots of trading data (specific details not provided in the code).

#### Connection Request

To subscribe to the Snapshot Stream:

* Use the same format as the BBO stream but with **Stream**: "snap".

```json
{
  "action": "subscribe",
  "stream": "snap",
  "base": "base_token",
  "quote": "quote_token",
  "ecosystem_book": true,
  "id": "unique_request_id"
}
```

#### Example Stream Output

{% code overflow="wrap" %}
```json
{
    "result": {
        "bids": ["1958", "0", 0], # 0 means the level was removed
        "asks": [
            ["1958", "4300", 2], # non zero means new volume on price level
            ...
        ],
        "msg_id": "3", // user can use this msg id to apply incremental update to snapshot that they query from rest
        "time": 1705221916000
    },
    "stream": "snap",
    "millis": 0,
    "ecosystem": true,
     "pair": {
        "base": "AETH",
        "quote": "AUSDC"
     }
}
```
{% endcode %}

### Unsubscribe from a Stream

To unsubscribe from any stream:

* **Action**: "unsubscribe"
* **Stream**: Specify the stream you want to unsubscribe from.
* **ID**: A unique request identifier.

```json
{
  "action": "unsubscribe",
  "stream": "specified_stream",
  "id": "unique_request_id"
}
```

#### Example Stream Output

```json
{
    "result": "OK",
    "id": 0
}
```

