> For the complete documentation index, see [llms.txt](https://docs.hydromancer.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hydromancer.xyz/readme/websocket/allmids.md).

# allMids

{% hint style="warning" %}

### ⚠️ This is an add-on endpoint - access has to be purchased separately.

{% endhint %}

Stream mid prices (`(best_bid + best_ask) / 2`) for every market in a single subscription, updated **every block** (\~70ms). Hyperliquid-compatible: clients that read `data.mids` work unchanged.

To minimize bandwidth, `allMids` sends **only the coins whose mid changed** on each block (a delta). The first message after subscribing is a full snapshot (`isSnapshot: true`); after that you receive changed-only deltas. The per-subscription `seq` is gap-free, so a seq jump signals a dropped message — reconnect to receive a fresh snapshot and resync. Apply each message by **merging** its `mids` into your local map.

For top-of-book bid/ask sizes use [`bbo`](/readme/websocket/bbo.md); for full depth use [`l2Book`](/readme/websocket/l2book.md); for mark/oracle/open-interest use [`allActiveAssetCtx`](/readme/websocket/allactiveassetctx.md).

### Subscribe

```json
{
    "method": "subscribe",
    "subscription": {
        "type": "allMids"
    }
}
```

With filters:

```json
{
    "method": "subscribe",
    "subscription": {
        "type": "allMids",
        "dex": "xyz",
        "marketTypes": ["perp", "spot", "outcome"]
    }
}
```

**Parameters:**

| Parameter     | Type      | Required | Description                                                                                                                                                                                                                                                                                                                                   |
| ------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dex`         | string    | No       | Filter by DEX prefix. `"main"` returns native coins (BTC, ETH, …); other values (e.g. `"xyz"`) return only coins with that prefix (`xyz:SP500`). Omit for all DEXes.                                                                                                                                                                          |
| `marketTypes` | string\[] | No       | Restrict to specific market types. Each entry is `"perp"`, `"spot"`, `"outcome"`, or the wildcard `"*"` (alone) for "every type the server currently tracks". Omitting the field defaults to `["perp"]` — spot and outcome markets do **not** appear unless you opt in. The default never grows; pass `["*"]` to auto-opt-in to future types. |

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

### Unsubscribe

```json
{
    "method": "unsubscribe",
    "subscription": {
        "type": "allMids"
    }
}
```

### Update data format

```json
{
    "channel": "allMids",
    "seq": 7,
    "cursor": "5123456:1704067200000",
    "data": {
        "mids": {
            "BTC": "70325.5",
            "ETH": "3228.25"
        },
        "time": 1704067200000,
        "blockHeight": 5123456,
        "isSnapshot": false
    }
}
```

When `isSnapshot` is `true`, `mids` is the complete set for your filter (sent once on subscribe). When `false`, `mids` contains only the coins that changed in that block. In both cases, merge `mids` into your local map.

### Field reference

| Field         | Type    | Description                                                              |
| ------------- | ------- | ------------------------------------------------------------------------ |
| `mids`        | object  | Map of coin symbol → mid price (decimal string)                          |
| `time`        | number  | Block timestamp (milliseconds since epoch)                               |
| `blockHeight` | number  | Block height this update was computed at                                 |
| `isSnapshot`  | boolean | `true` = full map (sent once on subscribe); `false` = changed-only delta |

### 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}`);
const mids = {}; // local map, merged on every message

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

    if (msg.type === 'connected') {
        ws.send(JSON.stringify({
            method: 'subscribe',
            subscription: { type: 'allMids' }
        }));
    } else if (msg.type === 'ping') {
        ws.send(JSON.stringify({ type: 'pong' }));
    } else if (msg.channel === 'allMids') {
        Object.assign(mids, msg.data.mids); // merge delta or snapshot
        console.log(`BTC mid: ${mids['BTC']} @ block ${msg.data.blockHeight}`);
    }
});
```

{% endtab %}

{% tab title="Python" %}

```python
import websocket
import json
import os

mids = {}  # local map, merged on every message

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

    if msg.get('type') == 'connected':
        ws.send(json.dumps({
            "method": "subscribe",
            "subscription": {"type": "allMids"}
        }))
    elif msg.get('type') == 'ping':
        ws.send(json.dumps({'type': 'pong'}))
    elif msg.get('channel') == 'allMids':
        mids.update(msg['data']['mids'])  # merge delta or snapshot
        print(f"BTC mid: {mids.get('BTC')} @ block {msg['data']['blockHeight']}")

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

{% endtab %}
{% endtabs %}

### Common errors

1. `Rate limit exceeded - allMids requires add-on permission` — your API key is missing the **allMids** add-on.
2. `Connection timeout` — respond to `ping` messages with `pong`.
3. `Invalid API key`
