> 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/rest-api/market-data/tpslbook.md).

# tpslBook

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

### Overview

The `tpslBook` endpoint returns a snapshot of all untriggered TP/SL orders (take profit, stop loss) across all markets. These are orders that exist on Hyperliquid but have **not yet been triggered** — they are not visible in the L4 orderbook.

**Key details:**

* \~110K trigger orders across \~330 markets (typical)
* Updated in real-time (per-block)
* Includes user address, trigger price, size, and order type for each order
* Use with [tpslUpdates](/readme/websocket/tpslupdates.md) WebSocket stream for real-time sync

## Request

**Endpoint:** `POST /info`

**All markets:**

```json
{
    "type": "tpslBook"
}
```

**Specific coins:**

```json
{
    "type": "tpslBook",
    "coins": ["BTC", "ETH"]
}
```

**Parameters:**

| Parameter | Type      | Required | Description                                      |
| --------- | --------- | -------- | ------------------------------------------------ |
| `coins`   | string\[] | No       | Specific markets to fetch. Omit for all markets. |

### Response

**Content-Type:** `application/octet-stream`

The response is a binary multi-zstd payload (\~4.2 MB for all markets, vs \~31 MB if served as JSON). Each market is compressed independently and concatenated with the same outer framing as [l4Book](/readme/rest-api/market-data/l4book.md). The SDK's `TpslClient` decodes this transparently — see [Streaming sync](#streaming-sync) below.

**Response headers:**

| Header             | Value                      |
| ------------------ | -------------------------- |
| `Content-Type`     | `application/octet-stream` |
| `x-payload-format` | `multi-zstd`               |
| `x-compression`    | `inner-zstd`               |

**Logical content (after decode):**

```json
{
    "height": 1012534610,
    "timestamp_ms": 1779884746878,
    "markets": [
        {
            "coin": "BTC",
            "orders": [
                {
                    "oid": 443601009265,
                    "coin": "BTC",
                    "user": "0x106cf0642235394d51cba33693ac49ce05262298",
                    "side": "B",
                    "triggerPx": "71000",
                    "limitPx": "63900",
                    "sz": "0.00789",
                    "triggerCondition": "Price below 71000",
                    "orderType": "Take Profit Market",
                    "isPositionTpsl": false,
                    "reduceOnly": true,
                    "timestamp": 1779821645206
                }
            ]
        }
    ]
}
```

### Response fields

| Field              | Type   | Description                              |
| ------------------ | ------ | ---------------------------------------- |
| `height`           | int    | Block height at the time of the snapshot |
| `timestamp_ms`     | int    | Block timestamp (ms since epoch)         |
| `markets`          | array  | Array of markets with trigger orders     |
| `markets[].coin`   | string | Market symbol                            |
| `markets[].orders` | array  | Trigger orders in this market            |

Order fields are the same as the [tpslUpdates](/readme/websocket/tpslupdates.md) `add` diff — see that page for full field descriptions.

<details>

<summary>Wire format (for non-SDK decoders)</summary>

All integers are little-endian. The SDK's [tpsl\_formats.py](https://github.com/hydromancerxyz/hydromancer-sdk/blob/main/src/hydromancer_sdk/_internal/tpsl_formats.py) is a \~100-line reference decoder.

**Outer framing:**

```
[count:u32_le][height:u64_le][timestamp_ms:u64_le]
  [blob_len:u32_le][blob_bytes] × count
```

| Field          | Bytes      | Description                                 |
| -------------- | ---------- | ------------------------------------------- |
| `count`        | 4          | Number of market blobs that follow          |
| `height`       | 8          | Block height of the snapshot                |
| `timestamp_ms` | 8          | Block timestamp (ms since epoch)            |
| `blob_len`     | 4          | Length in bytes of the next compressed blob |
| `blob_bytes`   | `blob_len` | zstd-compressed market payload (see below)  |

Markets are sorted by coin name. Coins with no trigger orders are omitted.

**Per-market blob:**

Each blob is `zstd(msgpack([coin, [order_tuples...]]))`. The msgpack uses positional arrays (not maps) for compactness — `rmp_serde::to_vec` on the Rust side. Each order is a 12-element array in struct-declaration order:

```
[oid, coin, user, side, trigger_px, limit_px, sz,
 trigger_condition, order_type, is_position_tpsl,
 reduce_only, timestamp]
```

| Index | Field               | Type   | Notes                                        |
| ----- | ------------------- | ------ | -------------------------------------------- |
| 0     | `oid`               | uint64 | Order ID                                     |
| 1     | `coin`              | string | Market symbol (matches outer `coin`)         |
| 2     | `user`              | string | User address (0x...)                         |
| 3     | `side`              | string | `"A"` (sell) or `"B"` (buy)                  |
| 4     | `trigger_px`        | string | Trigger price, decimal string                |
| 5     | `limit_px`          | string | Limit price, decimal string                  |
| 6     | `sz`                | string | Size, decimal string                         |
| 7     | `trigger_condition` | string | Human-readable condition                     |
| 8     | `order_type`        | string | E.g. `"Take Profit Market"`, `"Stop Market"` |
| 9     | `is_position_tpsl`  | bool   | `true` if attached to a position             |
| 10    | `reduce_only`       | bool   | `true` if reduce-only                        |
| 11    | `timestamp`         | uint64 | Order creation timestamp (ms)                |

</details>

### Streaming sync

To maintain a real-time view of trigger orders:

1. Subscribe to [tpslUpdates](/readme/websocket/tpslupdates.md) WebSocket stream
2. Fetch `tpslBook` snapshot — note the `height`
3. Apply buffered WS updates where `height > snapshot_height`
4. Continue applying live updates

See the [TP/SL heatmap streaming guide](/readme/builder-guides/tpsl-heatmap-streaming.md) for details.

### Rate limits

* 10 requests per 5 minutes

### Common errors

* **403**: Permission denied - check API key
* **429**: Rate limit exceeded
* **503**: Service unavailable - heatmap service is bootstrapping
