> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xo.market/llms.txt
> Use this file to discover all available pages before exploring further.

# Auto-cancellation

> Four reasons the orderbook can cancel your resting orders without an explicit DELETE.

If your resting orders disappear and you didn't issue `DELETE /order`, `DELETE /orders`, or `DELETE /cancel-all`, one of these four paths is the cause.

## 1. Heartbeat sweep (opt-in)

POSTing `/heartbeats` or `/v1/heartbeats` with valid L2 HMAC auth **opts your user into a safety net**: subsequent heartbeats must arrive within 30 seconds of each other, or every open order owned by your user is cancelled.

| Setting                   | Value                                                                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------- |
| Stale threshold           | 30 seconds without a heartbeat                                                                          |
| Sweep cadence             | every 5 seconds                                                                                         |
| Worst-case cancel latency | \~35 seconds after the last beat                                                                        |
| Opt-out                   | Stop calling `/heartbeats`. A user who has **never** successfully POSTed the endpoint is never tracked. |

<Warning>
  **SDK gotcha.** Both `py-clob-client.start_heartbeats()` and `rs-clob-client`'s heartbeat feature send these for you from a background task. If the background task dies (network blip, GC pause, process restart, event-loop block) without your main code noticing, your open orders get auto-cancelled \~30–35 seconds later. Either disable the SDK's heartbeat option or actively monitor the background task's health.
</Warning>

## 2. Balance rebalance

When the on-chain indexer reports a balance drop — a USDC withdrawal, an AMM trade, or a fill on another venue — the engine cancels enough resting orders to keep your remaining exposure within your new balance.

Cancellation order is **LIFO** (newest first), so your oldest resting orders are most likely to survive a rebalance.

The combined `/ws` channel emits an `orders_rebalanced` frame:

```json theme={null}
{
  "type": "orders_rebalanced",
  "cancelled_count": 2,
  "cancelled_order_ids": [
    "0x0011223344556677889900aabbccddeeff00112233445566778899aabbccddee",
    "0x1122334455667788990011223344556677889900aabbccddeeff112233445566"
  ]
}
```

On the canonical `/ws/user` channel, each affected order appears as a separate `order/CANCELLATION` frame.

## 3. Market lifecycle terminal transition

When a market transitions to **`Resolved`**, **`Voided`**, or **`Closed`** — see [Market lifecycle](/guides/market-lifecycle) — every open order in that market is cancelled atomically with the status change.

`Paused` is **not** in this set. Pausing freezes matching but retains resting orders; the market can resume to `Active` later.

WebSocket signature:

* `/ws/user` — one `order/CANCELLATION` frame per cancelled order, fanned out per user.
* Combined `/ws` — the bundled `market_status_changed` frame with `cancelled_orders > 0`.

## 4. GTD expiry sweep

Orders placed with `orderType: "GTD"` carry a signed `expiration` (Unix seconds). A background sweeper ticks every \~10 seconds, finds GTD orders past their expiration, and cancels them.

* WebSocket signature: `order/CANCELLATION` on `/ws/user` (or `order_cancelled` on combined `/ws`), with a reason flag indicating expiry.
* Typical cancel latency after the deadline: under 10 seconds.

GTD is the only order type that auto-cancels on a wall-clock deadline. GTC orders never expire on their own; FAK/FOK never rest, so expiry doesn't apply.

## Summary

| Cause             | Triggered by                                      | WS signature                                                         |
| ----------------- | ------------------------------------------------- | -------------------------------------------------------------------- |
| Heartbeat sweep   | You stopped sending `/heartbeats` after opting in | `order/CANCELLATION` per order                                       |
| Balance rebalance | On-chain balance drop                             | `orders_rebalanced` on `/ws`; per-order `CANCELLATION` on `/ws/user` |
| Market terminal   | Market `Resolved`/`Voided`/`Closed`               | `market_status_changed` + per-order `CANCELLATION`                   |
| GTD expiry        | Order's `expiration` reached                      | `order/CANCELLATION` per expired order                               |

If you see unexplained cancellations, this is the order to check: heartbeat status first (most common SDK footgun), then balance changes, then market status, then expirations.
