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

# orderCompletions

> Every order and TWAP on Hyperliquid that ends after being executed: fully filled, or a final status after a partial fill

Subscribe with `{"method":"subscribe","subscription":{"type":"orderCompletions"}}` to receive one event each time an order **ends after being executed**, for every user on Hyperliquid, with or without a builder code. Add `"users": ["0x...", ...]` (up to 20,000 addresses) to receive only the orders placed by those wallets, and/or `"builder": "0x..."` to receive only the orders placed with that builder code. Filters are applied on our side; see [Filters](#filters).

A fill on its own does not tell you whether more fills are coming. This channel does: when the event arrives, the order is over.

## What triggers an event

* **`filled`**: the order is fully filled (`sz` is `"0.0"`).

* **A final status after a partial fill**: `canceled`, `reduceOnlyCanceled`, `marginCanceled`, `selfTradeCanceled`, ... when part of the order was executed before it ended. Examples: an IOC or market order only partly filled, or a resting limit order canceled after a partial fill. `sz` is then the size left unfilled, so `origSz − sz` was executed.

* **The end of a TWAP** that executed at least part of its size: `finished`, `terminated`, `stopped` (TWAP with a stop price) or `error`, with its executed size and notional (see [TWAP ends](#twap-ends)).

Orders that end without any fill (cancels of untouched orders, rejections), TWAPs that end without executing anything, and intermediate states (`open`, `triggered`, `activated`) are not sent. For the full lifecycle of orders placed with your builder code, use [`orderUpdates` with `builder`](https://docs.hypedexer.com/live-data/ws-order-updates#filter-by-builder-code).

**Triggered TP/SL** orders appear as their own completion, under the `oid` of the order you placed: `status: "filled"`, `orderType` `Stop Market` / `Take Profit Market` (or their `Limit` variants), `triggerCondition: "Triggered"`, with their fills. **TWAP slices** do not appear one by one (Hyperliquid writes no order status for them): you get the end of the TWAP, and the slice fills on [`allFills`](https://docs.hypedexer.com/live-data/ws-all-fills) and [`userFills`](https://docs.hypedexer.com/live-data/ws-user-fills) with their `twapId`.

## Event shape

Same items as `orderUpdates` filtered by builder: Hyperliquid's `order`, `status` and `statusTimestamp`, plus:

* `user`: the wallet that placed the order;
* `builder`: `{"b": address, "f": fee in tenths of a basis point}`, or `null` for an order without a builder code;
* `fills`: the order's fills in the 30 seconds before it ended (its last block included), in Hyperliquid's fill shape: all of them for a market order. It can be `[]`, for example when an order partially filled long before is canceled: those fills went out on [`allFills`](https://docs.hypedexer.com/live-data/ws-all-fills) and [`userFills`](https://docs.hypedexer.com/live-data/ws-user-fills) when they happened.

```json theme={null}
{
  "channel": "orderCompletions",
  "data": [
    {
      "order": {"coin": "ETH", "side": "B", "limitPx": "3951.2", "sz": "0.0", "origSz": "2.5", "oid": 586400000002, "timestamp": 1793095817722, "orderType": "Market", "tif": "FrontendMarket", "reduceOnly": false, "isTrigger": false, "triggerPx": "0.0", "triggerCondition": "N/A", "isPositionTpsl": false, "children": [], "cloid": null},
      "status": "filled",
      "statusTimestamp": 1793095817722,
      "user": "0x3b8e1c2d4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c",
      "builder": null,
      "fills": [{"coin": "ETH", "px": "3949.8", "sz": "2.5", "side": "B", "time": 1793095817722, "dir": "Open Long", "oid": 586400000002, "tid": 1023400000000002, "fee": "3.555", "feeToken": "USDC", "crossed": true}]
    }
  ]
}
```

## TWAP ends

A TWAP end has no `order` and no `fills`; it carries `twapId` and the TWAP's state as `twap`, in Hyperliquid's shape (`executedSz` and `executedNtl` are the size and notional actually executed, `sz` the size asked for; `executedNtl / executedSz` is the average price):

```json theme={null}
{
  "twapId": 2400001,
  "status": "finished",
  "statusTimestamp": 1793123600000,
  "user": "0x3b8e1c2d4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c",
  "builder": null,
  "twap": {"coin": "ETH", "side": "A", "sz": "3.0", "executedSz": "3.0", "executedNtl": "7050.12", "minutes": 30, "randomize": false, "reduceOnly": false, "timestamp": 1793121800000, "stopPx": null, "trigger": null, "user": "0x3b8e1c2d4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c"}
}
```

Tell the two kinds apart by the presence of `twapId` (TWAP end) or `order` (order completion). The `users` filter applies to both.

## One event per order

An `oid` is unique across Hyperliquid and an order ends only once, so you receive one completion per `oid` (one per `twapId` for TWAPs). After a rare restart on our side, the events of the last second may be sent again: deduplicate on `oid` / `twapId`.

## Filters

| Parameter | Keeps |
| - | - |
| `users` | Completions of orders and TWAPs placed by these wallets (up to 20,000) |
| `builder` | Completions of orders placed with this builder code. TWAPs carry no builder code, so TWAP ends never match it. |

With both, an event is sent when it matches **either** (union): one connection can follow your builder code's orders and a list of other wallets. Any other parameter is refused with an error (for example `builders` instead of `builder`), so a typo never silently turns the subscription into the full stream. The acknowledgement echoes the filters in force: `{"type":"orderCompletions","users":15000,"builder":"0x..."}`.

## Subscribing with a list of wallets

```json theme={null}
{"method": "subscribe", "subscription": {"type": "orderCompletions", "users": ["0x...", "0x..."]}}
```

* Up to **20,000** addresses, 0x-prefixed, case-insensitive. The subscribe message must stay under **1 MB** (20,000 addresses take about 900 KB).
* The acknowledgement gives the number of addresses instead of echoing them: `{"channel":"subscriptionResponse","data":{"method":"subscribe","subscription":{"type":"orderCompletions","users":15000}}}`.
* One `orderCompletions` subscription per connection: subscribing again replaces the list. `{"method":"unsubscribe","subscription":{"type":"orderCompletions"}}` stops it.

## Volume and latency

About 60 to 100 events per second across all of Hyperliquid (October 2026), each about 1 s after its block (median 0.8–1.0 s, 95th percentile 1.3 s). There is no snapshot: it is a pure stream. To catch up after a disconnect, or to read a past window, use the REST counterpart `POST /info` with `{"type":"orderCompletions","startTime":...}` (Live Data REST API, *Account History*): same entries, paged, with the same optional `users` and `builder` filters, 90 days of history.

Usage is billed as standard WebSocket events against your plan's credits.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.