# builderLiquidations

Note: TWAP fills do not carry builder codes. If a user's last fill before liquidation was a TWAP fill, no builder liquidation notification will be sent.

{% 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
{ 
  "type": "subscribe", 
  "subscription": { 
    "type": "builderLiquidations", 
    "builder": "0x..", // your builder address
    "aggregateByTime": true
  }
}

```

### Parameters

<table><thead><tr><th>Parameter</th><th width="117.7105712890625">Type</th><th width="118.0491943359375">Required</th><th width="108.1435546875">Default</th><th>Description</th></tr></thead><tbody><tr><td>builder</td><td>string</td><td>Yes</td><td>-</td><td>Your builder address</td></tr><tr><td>dex</td><td>string</td><td>No</td><td>null</td><td>Filter by DEX: "xyz", "main" ( for fills only on first dex)</td></tr><tr><td>aggregateByTime</td><td>boolean</td><td>No</td><td>true</td><td>Aggregate multi-fill liquidations by (user, time, order_id)</td></tr></tbody></table>

### Unsubscribe

**note: make sure to use exactly the same message as subscription message.**

```json
{ 
  "type": "unsubscribe", 
  "subscription": { 
    "type": "builderLiquidations", 
    "builder": "0x..",
    "aggregateByTime": true
  } 
}
```

### Liquidation data format

{% hint style="info" %}
**Reconnection Note:** When reconnecting with a session, replay and live events may overlap. Deduplicate using `(time, txIndex)` - skip liquidation fills where this tuple is at or before your last processed fill. See [Session Management](/readme/websocket/session-management-and-reconnection.md#deduplication) for details.
{% endhint %}

Each message contains an array of liquidation fills. Each fill is a tuple of \[user\_address, fill\_data].

```json
{ 
  "type": "builderLiquidations", 
  "seq": 1,
  "cursor": "500:1704067200000:3",
  "liquidations": [ 
    [ 
      "0x742d35cc6634c0532925a3b844bc9e7595f7f2e2", 
      { 
        "coin": "ETH", 
        "px": "2150.50", 
        "sz": "1.5", 
        "side": "A", 
        "time": 1704067200000, 
        "startPosition": "1.5", 
        "dir": "Close Long", 
        "closedPnl": "-125.50", 
        "hash": "0xabc...def", 
        "oid": 12345678, 
        "crossed": true, 
        "fee": "2.50", 
        "tid": 87654321, 
        "cloid": null, 
        "builderFee": null,
        "deployerFee": null,
        "feeToken": "USDC",
        "builder": "0x..", // my builder address
        "twapId": null, 
        "txIndex": 1, 
        "liquidation": { 
          "liquidatedUser": "0x742d35cc6634c0532925a3b844bc9e7595f7f2e2", 
          "markPx": "2148.00", 
          "method": "market"
         }, 
         "user": "0x742d35cc6634c0532925a3b844bc9e7595f7f2e2" 
       } 
     ] 
   ] 
 }
```

### 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('message', (data) => {
    const msg = JSON.parse(data);

    if (msg.type === 'connected') {
        // Subscribe to builder liquidations
        ws.send(JSON.stringify({
            type: 'subscribe',
            subscription: {
                type: 'builderLiquidations',
                builder: 'YOUR_BUILDER_CODE'
            }
        }));
    } else if (msg.type === 'ping') {
        ws.send(JSON.stringify({ type: 'pong' }));
    } else if (msg.type === 'builderLiquidations') {
        console.log(`Received ${msg.liquidations.length} liquidation fills`);
        for (const [user, fill] of msg.liquidations) {
            console.log(`User ${user} liquidated: ${fill.sz} ${fill.coin} @ ${fill.px}`);
            if (fill.liquidation) {
                console.log(`  Liquidated user: ${fill.liquidation.liquidatedUser}`);
                console.log(`  Mark price: ${fill.liquidation.markPx}`);
            }
        }
    }
});
```

{% endtab %}

{% tab title="Python" %}

```python
import websocket
import json
import os

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

    if msg['type'] == 'connected':
        ws.send(json.dumps({
            'type': 'subscribe',
            'subscription': {
                'type': 'builderLiquidations',
                'builder': 'YOUR_BUILDER_CODE'
            }
        }))
    elif msg['type'] == 'ping':
        ws.send(json.dumps({'type': 'pong'}))
    elif msg['type'] == 'builderLiquidations':
        print(f"Received {len(msg['liquidations'])} liquidation fills")
        for user, fill in msg['liquidations']:
            print(f"User {user}: {fill['sz']} {fill['coin']} @ {fill['px']}")

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

{% endtab %}
{% endtabs %}

#### Error messages:

```
{
    "type": "error",
    "message": "Invalid API key"
}
```

#### Common errors

1. ```
   Connection timeout - Respond to ping messages
   ```
2. ```
   Too many subscriptions - Maximum builder subscriptions per API key
   ```
3. ```
   Invalid builder code
   ```
4. ```
   Invalid 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/builderliquidations.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.
