# 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
}
```


---

# Agent Instructions: 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:

```
GET https://layer-akira.gitbook.io/layerakira-documentation/integration/endpoints/stream-subscriptions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
