# l4BookUpdates

{% hint style="info" %}
💧 New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

### Subscribe

```json
{
    "method": "subscribe",
    "subscription": {
        "type": "l4BookUpdates",
        "coins": ["ETH", "BTC"]
    }
}
```

**Parameters:**

| Parameter     | Type      | Required | Description                                                                                                                           |
| ------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `coins`       | string\[] | No       | Coins to subscribe to. Omit for all markets (needs **l4BookUpdatesAll** add-on).                                                      |
| `marketTypes` | string\[] | No       | All-markets only. Filters delivery by market type — see [All-markets filter](#all-markets-filter). Rejected if combined with `coins`. |

### All-markets filter

When `coins` is omitted, the optional `marketTypes` field restricts the firehose to specific market types. Each entry is `"perp"`, `"spot"`, `"outcome"`, or the wildcard `"*"` (alone) for "every type the server currently tracks":

```json
{
    "method": "subscribe",
    "subscription": {
        "type": "l4BookUpdates",
        "marketTypes": ["perp", "outcome"]
    }
}
```

Omitting `marketTypes` defaults to `["perp"]` — outcome and spot markets do **not** appear unless you opt in. The default never grows; new market types must be added to your `marketTypes` array explicitly. Pass `["*"]` to auto-opt-in to future types.

A second subscribe with a different `marketTypes` value **replaces** the previous filter rather than coexisting with it.

### Unsubscribe

```json
{
    "method": "unsubscribe",
    "subscription": {
        "type": "l4BookUpdates",
        "coins": ["ETH", "BTC"]
    }
}
```

### Update data format

Updates are streamed per-block with order changes for subscribed markets:

```json
{
    "type": "l4BookUpdates",
    "seq": 1,
    "cursor": "500:1704067200000",
    "data": {
        "height": 782007304,
        "timestamp": 1704067200000,
        "diffs": [
            {
                "type": "new",
                "coin": "ETH",
                "oid": 217148811876,
                "user": "0x742d35cc6634c0532925a3b844bc9e7595f7f2e2",
                "side": "B",
                "px": "3245.50",
                "sz": "1.5"
            },
            {
                "type": "update",
                "coin": "ETH",
                "oid": 217148811800,
                "sz": "2.0"
            },
            {
                "type": "remove",
                "coin": "ETH",
                "oid": 217148811750
            }
        ]
    }
}
```

### Diff types

| Type     | Description                       | Fields                                    |
| -------- | --------------------------------- | ----------------------------------------- |
| `new`    | New order placed                  | `coin`, `oid`, `user`, `side`, `px`, `sz` |
| `update` | Order size changed (partial fill) | `coin`, `oid`, `sz`                       |
| `remove` | Order removed (filled/cancelled)  | `coin`, `oid`                             |

### Field definitions

| Field       | Type   | Description                        |
| ----------- | ------ | ---------------------------------- |
| `height`    | int    | Block height                       |
| `timestamp` | int    | Block timestamp (ms since epoch)   |
| `coin`      | string | Market symbol (e.g., "ETH", "BTC") |
| `oid`       | int    | Unique order ID                    |
| `user`      | string | User address (0x...)               |
| `side`      | string | "B" = bid, "A" = ask               |
| `px`        | string | Price as decimal string            |
| `sz`        | string | Size as decimal string             |

### Examples

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

```javascript
const WebSocket = require('ws');

const ws = new WebSocket(`wss://api.hydromancer.xyz/ws?token=${process.env.HYDROMANCER_API_KEY}`);

ws.on('open', () => {
    ws.send(JSON.stringify({
        method: 'subscribe',
        subscription: {
            type: 'l4BookUpdates',
            coins: ['ETH', 'BTC']
        }
    }));
});

ws.on('message', (data) => {
    const msg = JSON.parse(data);

    if (msg.type === 'ping') {
        ws.send(JSON.stringify({ method: 'pong' }));
    } else if (msg.type === 'l4BookUpdates') {
        const { height, diffs } = msg.data;
        console.log(`Height ${height}: ${diffs.length} order changes`);
    }
});
```

{% endtab %}

{% tab title="Python" %}

```python
import websocket
import json
import os

def on_message(ws, message):
    msg = json.loads(message)

    if msg.get('type') == 'ping':
        ws.send(json.dumps({'method': 'pong'}))
    elif msg.get('type') == 'l4BookUpdates':
        data = msg['data']
        print(f"Height {data['height']}: {len(data['diffs'])} order changes")

def on_open(ws):
    ws.send(json.dumps({
        "method": "subscribe",
        "subscription": {
            "type": "l4BookUpdates",
            "coins": ["ETH", "BTC"]
        }
    }))

if __name__ == "__main__":
    api_key = os.environ.get('HYDROMANCER_API_KEY')
    ws = websocket.WebSocketApp(f'wss://api.hydromancer.xyz/ws?token={api_key}',
                                on_open=on_open,
                                on_message=on_message)
    ws.run_forever()
```

{% endtab %}
{% endtabs %}

### Common errors

1. `Too many coins` - Reduce number of coins or upgrade tier
2. `Subscribing to all markets requires permission` - Needs add-on for all books
3. `Rate limit exceeded` - Reduce subscription frequency
4. `Authentication failed` - Check API key


---

# 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://docs.hydromancer.xyz/readme/websocket/l4bookupdates.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.
