# Fills Channel


Source: https://docs.stxapp.io/websockets/channels/fills/

Topic: `fills:{user_id}`

Delivers **your** executions as they trade and settle. Money arrives as dollar
strings and contract counts as quantity strings; see
[Wire format](/websockets/channels/wire-format/).

To look up what one order filled at after the fact, call
[`GET /api/v1/fills?order_ids=<order_id>`](/api/rest/fills/list-fills/). It takes
several comma-separated order ids, combines with `market_ids` and `status`, and
pages by `cursor` like the unfiltered list.

:::caution[`fills` is not the market-wide `trades` topic]
`fills:{user_id}` is yours. [`trades`](/websockets/channels/market-data/#trades) is
every participant's, anonymized. They are different feeds and are not
interchangeable.
:::

## Fill object

### Identity and provenance

- `id` : The unique id of the trade.
- `market_id` : The id of the market the trade is on.
- `order_id` : The id of the order this trade belongs to.
- `client_order_id` : The client-supplied id of the order that created this trade,
  if any.
- `liquidity_action` : Whether the linked order was a liquidity `provider` or
  `taker`.
- `device_id` : The device id from the order that created this trade. Null if the
  order didn't carry one.
- `ip_address` : The IP address from the order that created this trade. Null if the
  order didn't carry one.

### Lifecycle

- `action` : Whether the trade is a `buy` or a `sell`.
- `status` : `created`, `open`, `settled` or `cancelled`.
- `time` : When the trade was created, ISO 8601.
- `inserted_at` : The same instant, as an integer in Unix microseconds.
- `settled_at` : When the trade's status became `settled`, ISO 8601. Null until
  then, and stays null if the trade is cancelled instead.
- `expires_at` : When the traded contracts expire, as an integer in Unix
  microseconds. Null when unknown.
- `amended` : Whether STX has changed the trade's price after it executed.
- `settlements_count` : The number of settlements where this trade was the opening
  side. An integer, not a quantity string.

### Contracts

All quantity strings.

- `filled` : The number of contracts this trade represents. Can be fractional.
- `remaining` : How many of the trade's contracts are still unsettled.
- `closing` : How many of the trade's contracts close an opposing position, rather
  than opening a new one. Zero for a purely opening trade.
- `closed_contracts` : How many contracts were closed by a later trade.
- `expired_contracts` : How many contracts were settled at market expiry.

### Price and premium

All dollar strings.

- `price` : The price the trade executed at.
- `premium` : The premium paid or received for the trade (`filled` × `pc_premium`).
- `pc_premium` : The premium per contract. On a **sell** this is `price`, the premium
  you receive; on a **buy** it is `-price`, the premium you pay, so this field is
  negative on every buy.
- `pc_risk` : The risk per contract: `price` on a buy, `max_price - price` on a
  sell.
- `pc_to_win` : What each contract gains if the position wins: `max_price - price`
  on a buy, `price` on a sell. It is **not** the same as `pc_risk`; the two are only equal at
  the midpoint.
- `remaining_premium` : The premium on the unsettled portion.
- `remaining_risk` : The risk on the unsettled portion.
- `remaining_to_win` : What the unsettled portion gains if the position wins.
- `original_premium` : The premium the trade represented once finalized, excluding
  any portion later used to close an opposing position.
- `original_risk` : The same, for risk.
- `original_to_win` : The same, for the gain if the position wins.

### Profit, loss and fees

All dollar strings.

- `gross_pnl` : The trade's profit or loss before fees, accruing as settlements
  land.
- `closed_pnl` : Profit or loss from contracts closed by a later trade.
- `expired_pnl` : Profit or loss from contracts settled at market expiry.
- `trade_fee` : The fee charged for this trade specifically.
- `total_fee` : The all-in fee: `trade_fee` plus the settlement fees this trade has
  incurred. **This is the fee to display.** See
  [`total_fee`](/websockets/channels/wire-format/#total_fee-is-the-all-in-fee).
- `closed_fee` : The fee paid on contracts closed by a later trade.
- `expired_fee` : The fee paid on contracts settled at market expiry.
- `remaining_potential_fee` : The maximum fee that could still be charged on the
  unsettled portion.
- `max_potential_fee` : Identical to `remaining_potential_fee`. It does
  not include fees already charged on the settled portion.

### Loyalty

- `points` : Loyalty points earned from the trade, updated as it settles. A number
  rounded to two places, not a money string.

## Use Cases

| Use case | Message to send |
| --- | --- |
| Join and receive your open trades | `["3","3","fills:<user_id>","phx_join",{}]` |
| Join filtered to one market (see [filtering](/websockets/channels/wire-format/#filtering)) | `["3","3","fills:<user_id>","phx_join",{"market_ids":["<uuid>"]}]` |
| Change the market filter without rejoining | `["3","4","fills:<user_id>","select_market_ids",{"market_ids":null}]` |
| Check the connection is alive | `["3","5","fills:<user_id>","ping",{}]` |

### Joining

```json
["3","3","fills:<user_id>","phx_join",{}]
```

```json
{"status":"ok","response":{"selected_market_ids":null}}
```

### Initial response after joining

```json
[null, null, "fills:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "all_trades", { "trades": [Fill]}]
```

`trades` is a list of `Fill` objects, described above, empty if you have none open,
and also empty when a `market_ids` filter matches nothing.

```json
[
  null,
  null,
  "fills:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "all_trades",
  {
    "trades": [
      {
        "id": "787582ec-3863-4760-bbcb-398d3dca8fe5",
        "market_id": "687e9cdb-a391-4118-aa80-1122bb14779f",
        "order_id": "c1c3614c-32ae-4bea-bae4-fc3f52047790",
        "client_order_id": null,
        "liquidity_action": "provider",
        "device_id": "web-chrome-114",
        "ip_address": "203.0.113.42",
        "status": "open",
        "time": "2026-11-01T19:20:34.890853Z",
        "inserted_at": 1793640034890853,
        "settled_at": null,
        "expires_at": 1825736399999999,
        "amended": false,
        "settlements_count": 1,
        "action": "sell",
        "filled": "20.00",
        "remaining": "10.00",
        "closing": "0.00",
        "closed_contracts": "10.00",
        "expired_contracts": "0.00",
        "price": "0.2400",
        "premium": "4.8000",
        "pc_premium": "0.2400",
        "pc_risk": "0.7600",
        "pc_to_win": "0.2400",
        "remaining_premium": "2.4000",
        "remaining_risk": "7.6000",
        "remaining_to_win": "2.4000",
        "original_premium": "4.8000",
        "original_risk": "15.2000",
        "original_to_win": "4.8000",
        "gross_pnl": "1.2000",
        "closed_pnl": "1.2000",
        "expired_pnl": "0.0000",
        "trade_fee": "0.0600",
        "total_fee": "0.1200",
        "closed_fee": "0.0600",
        "expired_fee": "0.0000",
        "remaining_potential_fee": "0.3800",
        "max_potential_fee": "0.3800",
        "points": 20.0
      }
    ]
  }
]
```

### Pushed when a trade is created or updated

One frame **per trade**, not a batch, including trades that just transitioned to
`settled` or `cancelled`, so clients can drop them from their active view. An order
that sweeps several resting orders therefore produces several frames.

```json
[null, null, "fills:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "trade", Fill]
```

```json
[
  null,
  null,
  "fills:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "trade",
  {
    "id": "787582ec-3863-4760-bbcb-398d3dca8fe5",
    "market_id": "687e9cdb-a391-4118-aa80-1122bb14779f",
    "order_id": "c1c3614c-32ae-4bea-bae4-fc3f52047790",
    "client_order_id": null,
    "liquidity_action": "provider",
    "device_id": "web-chrome-114",
    "ip_address": "203.0.113.42",
    "status": "settled",
    "time": "2026-11-01T19:20:34.890853Z",
    "inserted_at": 1793640034890853,
    "settled_at": "2026-11-01T19:25:10.221450Z",
    "expires_at": 1825736399999999,
    "amended": false,
    "settlements_count": 2,
    "action": "sell",
    "filled": "20.00",
    "remaining": "0.00",
    "closing": "0.00",
    "closed_contracts": "20.00",
    "expired_contracts": "0.00",
    "price": "0.2400",
    "premium": "4.8000",
    "pc_premium": "0.2400",
    "pc_risk": "0.7600",
    "pc_to_win": "0.2400",
    "remaining_premium": "0.0000",
    "remaining_risk": "0.0000",
    "remaining_to_win": "0.0000",
    "original_premium": "4.8000",
    "original_risk": "15.2000",
    "original_to_win": "4.8000",
    "gross_pnl": "3.0000",
    "closed_pnl": "3.0000",
    "expired_pnl": "0.0000",
    "trade_fee": "0.0600",
    "total_fee": "0.2100",
    "closed_fee": "0.1500",
    "expired_fee": "0.0000",
    "remaining_potential_fee": "0.0000",
    "max_potential_fee": "0.0000",
    "points": 20.0
  }
]
```
