> 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/tpslupdates.md).

# tpslUpdates

Every live data message includes both routing identifiers with the same value:

```json
{"type": "tpslUpdates", "channel": "tpslUpdates"}
```

Other payload fields are omitted above. Existing clients may continue routing on either field.

{% 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": "tpslUpdates",
        "coins": ["ETH", "BTC"]
    }
}
```

**Parameters:**

| Parameter | Type      | Required | Description                                                                         |
| --------- | --------- | -------- | ----------------------------------------------------------------------------------- |
| `coins`   | string\[] | No       | Perp coins to subscribe to. Omit for all markets (needs **tpslUpdatesAll** add-on). |

**Per-tier coin limits:** Starter 5 · Growth 50 · Scale 200. See [rate-limits-user-limits-and-heartbeats.md](/readme/websocket/rate-limits-user-limits-and-heartbeats.md) for the full table.

{% hint style="warning" %}
Trigger orders only exist on **perpetual markets**. Spot and outcome markets do not have TP/SL orders, so no `marketTypes` filter is needed.
{% endhint %}

### Unsubscribe

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

### Update data format

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

```json
{
    "type": "tpslUpdates",
    "channel": "tpslUpdates",
    "seq": 1,
    "cursor": "500:1704067200000",
    "data": {
        "height": 782007304,
        "timestamp": 1704067200000,
        "diffs": [
            {
                "type": "add",
                "oid": 285974866067,
                "coin": "BTC",
                "user": "0x742d35cc6634c0532925a3b844bc9e7595f7f2e2",
                "side": "A",
                "triggerPx": "50000.00",
                "limitPx": "49000",
                "sz": "0.01",
                "triggerCondition": "Price above 50000",
                "orderType": "Take Profit Market",
                "isPositionTpsl": true,
                "reduceOnly": true,
                "timestamp": 1704067100000
            },
            {
                "type": "remove",
                "oid": 285974866000,
                "coin": "BTC",
                "reason": "triggered"
            }
        ]
    }
}
```

### Diff types

| Type     | Description                             | Fields                       |
| -------- | --------------------------------------- | ---------------------------- |
| `add`    | New trigger order placed (or re-opened) | All order fields (see below) |
| `remove` | Trigger order removed                   | `oid`, `coin`, `reason`      |

Trigger orders are **immutable** — there is no `update` diff type. An order is either open (`add`) or terminal (`remove`). If a user cancels and replaces a trigger order, you'll see a `remove` + `add` with a new `oid`.

### Add fields

| Field              | Type   | Description                                                     |
| ------------------ | ------ | --------------------------------------------------------------- |
| `oid`              | int    | Unique order ID                                                 |
| `coin`             | string | Market symbol (e.g., "BTC", "ETH")                              |
| `user`             | string | User address (0x...)                                            |
| `side`             | string | "B" = buy, "A" = sell                                           |
| `triggerPx`        | string | Trigger price as decimal string                                 |
| `limitPx`          | string | Limit price as decimal string                                   |
| `sz`               | string | Order size as decimal string                                    |
| `triggerCondition` | string | Human-readable condition (e.g., "Price above 50000")            |
| `orderType`        | string | Order type — "Take Profit Market", "Stop Market", etc.          |
| `isPositionTpsl`   | bool   | True if this is a position-level TP/SL (attached to a position) |
| `reduceOnly`       | bool   | True if reduce-only order                                       |
| `timestamp`        | int    | Order creation timestamp (ms since epoch)                       |

### Remove handling

A `remove` diff is always terminal — drop the order from your local state. The optional `reason` field is informational only; you don't need to branch on it.

<details>

<summary>Known reason values (for logging / analytics)</summary>

| Reason                  | Description                                      |
| ----------------------- | ------------------------------------------------ |
| `triggered`             | Trigger condition met, order placed on book      |
| `canceled`              | User canceled the order                          |
| `reduceOnlyCanceled`    | Reduce-only order canceled (position closed)     |
| `marginCanceled`        | Canceled due to insufficient margin              |
| `rejected`              | Order rejected by the engine                     |
| `siblingFilledCanceled` | Sibling TP/SL order triggered, this one canceled |
| `liquidatedCanceled`    | Order canceled due to position liquidation       |

The `reason` field passes through the underlying Hyperliquid status verbatim, so future status names will appear automatically. Always treat a `remove` diff as terminal regardless of the reason value.

</details>

### Common errors

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