> For the complete documentation index, see [llms.txt](https://mute-sh.gitbook.io/mute.sh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mute-sh.gitbook.io/mute.sh/api/api-reference/fills-and-activity.md).

# Fills & Live Activity

Three ways to consume HIP-4 trade flow, from historical to live:

| Endpoint                  | What it is                                                          | Reach             |
| ------------------------- | ------------------------------------------------------------------- | ----------------- |
| `GET /v1/fills`           | Queryable fill archive — filter by wallet, coin, direction, builder | full history      |
| `GET /v1/activity`        | The most recent fills + settlements (in-memory ring, newest first)  | last \~200 events |
| `GET /v1/activity/stream` | Live SSE push of every fill + settlement as it lands                | now               |

Rule of thumb: **backfill from `/fills`, render "recent activity" from `/activity`, stay current with `/activity/stream`.** Polling `/fills` in a loop is the anti-pattern the stream exists to replace.

***

## GET /v1/fills

The workhorse: paginated raw fills with server-side filters. **At least one of `user` or `coin` is required** — there is deliberately no "give me everything" query (that's what the stream is for).

| Query param | Type    | Default | Description                                                   |
| ----------- | ------- | ------- | ------------------------------------------------------------- |
| `user`      | address | —       | trader wallet (lowercased internally)                         |
| `coin`      | string  | —       | exact coin, e.g. `%231541` (`#1541`)                          |
| `dir`       | string  | —       | exact direction — see [the `dir` taxonomy](#the-dir-taxonomy) |
| `builder`   | address | —       | fills routed via this builder (lowercased internally)         |
| `limit`     | int     | `100`   | capped at 1000                                                |
| `offset`    | int     | `0`     | pagination                                                    |

All filters AND-combine. When filtering by `user` alone the query runs against a user-ordered replica, so wallet history pages are fast even for very active accounts.

```bash
# a wallet's latest fills, everywhere
curl -H "X-API-Key: $MUTE_KEY" \
  "https://api.mute.sh/v1/fills?user=0xd9ee2b58b061d62d8090f4cba11b5c2043b0cd0c&limit=2"
```

```json
{
  "data": [
    {
      "time": "2026-07-05 08:25:50.041",
      "coin": "#1990",
      "side": "B",
      "dir": "Buy",
      "px": 0.02756,
      "sz": 1207,
      "fee": 0,
      "fee_token": "+1990",
      "closed_pnl": 0,
      "crossed": false,
      "start_position": 86001,
      "user": "0xd9ee2b58b061d62d8090f4cba11b5c2043b0cd0c",
      "oid": 487782039352,
      "tid": 576713512519452,
      "hash": "0x08b24ca62ad1e6bb0a2c043f40ebf0015d00648bc5d5058dac7af7f8e9d5c0a5",
      "builder": "",
      "builder_fee": 0
    },
    {
      "time": "2026-07-05 08:25:00.042",
      "coin": "#1890",
      "side": "A",
      "dir": "Sell",
      "px": 0.35714,
      "sz": 25,
      "fee": 0,
      "fee_token": "USDC",
      "closed_pnl": 6.73676936,
      "crossed": true,
      "start_position": 171415,
      "user": "0xd9ee2b58b061d62d8090f4cba11b5c2043b0cd0c",
      "oid": 487781850910,
      "tid": 41778698411397,
      "hash": "0xe48318eb555e6cf0e5fc043f40e94a02010300d0f0518bc2884bc43e145246db",
      "builder": "",
      "builder_fee": 0
    }
  ],
  "limit": 2,
  "offset": 0
}
```

### Field reference

| Field               | Type            | Meaning                                                                                                                                |
| ------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `time`              | string          | UTC, `YYYY-MM-DD HH:MM:SS.mmm`, newest first                                                                                           |
| `coin`              | string          | the `#N` coin this fill executed on (one side of the pair)                                                                             |
| `side`              | `A`/`B`         | order-book side of the fill                                                                                                            |
| `dir`               | string          | fill classification — see below                                                                                                        |
| `px`                | number          | price in `(0,1)` — the probability paid. Settlement fills print `1` (winner) or `0` (loser)                                            |
| `sz`                | number          | size in outcome shares; `px·sz` = USD notional                                                                                         |
| `fee` / `fee_token` | number / string | fee and the token it was charged in: `USDC`, or **in-kind** `+N` (e.g. `+1990` — fee taken in shares of coin `#1990`, typical on Buys) |
| `closed_pnl`        | number          | realized USD PnL — `0` on opening fills, populated on Sells/Settlements                                                                |
| `crossed`           | boolean         | `true` = taker (crossed the spread), `false` = maker                                                                                   |
| `start_position`    | number          | the user's position in shares *before* this fill                                                                                       |
| `oid` / `tid`       | number          | HyperCore order ID / globally-unique trade ID                                                                                          |
| `hash`              | string          | L1 action hash. All Settlement fills of one market share **one hash** — a single settlement action fanned out to every holder          |
| `builder`           | string          | builder address that routed the order, `""` for direct flow                                                                            |
| `builder_fee`       | number          | builder fee in USD                                                                                                                     |

### The `dir` taxonomy

`dir` carries seven values, and **only two are trades**:

| `dir`                                                                | What it is                                                          |
| -------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `Buy` / `Sell`                                                       | real trading activity                                               |
| `Settlement`                                                         | the payout sweep at market resolution (winner `px=1`, loser `px=0`) |
| `Negate Outcome`, `Split Outcome`, `Merge Outcome`, `Merge Question` | AMM inventory plumbing — share conversions, not bets                |

For "betting volume" style analytics, filter `dir=Buy` (and `Sell` for exits). Counting plumbing rows as trades is the single most common integration mistake — a `Negate Outcome` at `px=1.0` looks like a huge confident bet and isn't.

```bash
# only real buys on a market, routed through any builder
curl -H "X-API-Key: $MUTE_KEY" \
  "https://api.mute.sh/v1/fills?coin=%231541&dir=Buy&limit=100"
```

### Errors

| Case                      | Response                               |
| ------------------------- | -------------------------------------- |
| neither `user` nor `coin` | `400` `"Provide user or coin"`         |
| malformed address         | `400` `"Invalid address"`              |
| malformed coin            | `400` `"Invalid coin"`                 |
| valid filters, no matches | `200` with `"data": []` — not an error |

**Caching:** none — responses are dynamic and uncached (no `Cache-Control` header is sent).

***

## GET /v1/activity

The shared recent-events feed: fills **and settlements** across all markets, newest first, straight from an in-memory ring of the last \~200 events. **Public — no key required** (this endpoint and its stream are metered at the free anonymous bucket for everyone, by IP; they're the product's free wedge).

| Query param    | Type    | Default | Description                                             |
| -------------- | ------- | ------- | ------------------------------------------------------- |
| `limit`        | int     | `50`    | 1–200                                                   |
| `min_notional` | number  | —       | whale filter: only events with `px·sz ≥` this USD value |
| `side`         | `A`/`B` | —       | order-book leg filter                                   |

(`builder` and `category` are accepted and shape-validated but currently **not applied** to the feed — sending them doesn't filter anything. They're reserved.)

```bash
curl "https://api.mute.sh/v1/activity?min_notional=1000&limit=3"
```

```json
{
  "events": [
    {
      "type": "fill",
      "time": "2026-07-05 08:28:25.670",
      "ts_ms": 1783240105670,
      "coin": "#7391",
      "outcome_id": 739,
      "side_idx": 1,
      "side": "B",
      "px": 0.295,
      "sz": 4052,
      "notional": 1195.34,
      "dir": "Buy",
      "tid": 481763898558141
    }
  ]
}
```

### Event shape

Leaner than a `/fills` row, and enriched for rendering:

| Field                              | Meaning                                                                                                                                             |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                             | `fill` or `settlement` (`settlement` = the fill's `dir` is `Settlement`)                                                                            |
| `time` / `ts_ms`                   | same instant twice: display string (UTC) and epoch milliseconds for sorting                                                                         |
| `coin` / `outcome_id` / `side_idx` | the coin, its parent market ID, and which side of the pair (`0` = even/Up coin, `1` = odd/Down coin) — no extra lookup needed to group the two legs |
| `notional`                         | precomputed `px·sz` USD — what `min_notional` filters on                                                                                            |
| `dir`                              | same taxonomy as `/fills` — plumbing ops (`Merge Outcome` etc.) appear here too                                                                     |
| `tid`                              | trade ID, use as your dedup key                                                                                                                     |

Filters run server-side against the full ring, so `min_notional=1000&limit=3` returns up to 3 *matching* events, not 3 raw events that then get filtered away. Malformed filters are `400`s (`Invalid side (expected A or B)`, `Invalid min_notional`).

***

## GET /v1/activity/stream

The same events, pushed live over **Server-Sent Events**. Public like the list endpoint; keyed callers use `?apikey=` (the browser `EventSource` API can't set headers).

```bash
curl -N "https://api.mute.sh/v1/activity/stream?apikey=$MUTE_KEY&min_notional=500"
```

Raw wire format, exactly as captured:

```
: connected 2026-07-05T10:06:45.947Z

event: fill
data: {"type":"fill","time":"2026-07-05 08:28:25.670","ts_ms":1783240105670,"coin":"#7390","outcome_id":739,"side_idx":0,"side":"B","px":0.705,"sz":4052,"notional":2856.66,"dir":"Buy","tid":680060045725143}

event: fill
data: {"type":"fill","time":"2026-07-05 08:28:25.670","ts_ms":1783240105670,"coin":"#7391","outcome_id":739,"side_idx":1,"side":"B","px":0.29502,"sz":4052,"notional":1195.34,"dir":"Buy","tid":481763898558141}

: ping 1783246007334
```

### Stream semantics

* **Event names:** `fill` and `settlement` — the SSE `event:` name mirrors the payload's `type`; the JSON shape is identical to `/v1/activity` events.
* **On connect:** a `: connected <ISO time>` comment, then a **replay of the last 10 events, oldest-first**, so your UI renders instantly — then the live tail. Your filters apply to the replay too.
* **Filters:** `min_notional` and `side`, same as the list endpoint, applied server-side — filtered-out events never cross the wire. Malformed filters fail as a plain JSON `400` *before* the stream opens.
* **Heartbeat:** a `: ping <epoch_ms>` comment every \~25 s keeps proxies from idling the connection. Comments (`:` lines) are ignored by `EventSource` automatically.
* **Caps:** 500 concurrent streams server-wide, **3 per key/IP**, and a **30-minute maximum lifetime** per connection — the server ends the stream and frees the slot. Reconnect and resume; treat it as routine.
* **At capacity:** you get an `event: error` frame (`{"error":"stream at capacity, retry later"}`) and the stream closes.

### Client pattern

```js
function connect() {
  const es = new EventSource(
    "https://api.mute.sh/v1/activity/stream?apikey=" + KEY + "&min_notional=1000"
  );
  const seen = new Set(); // dedup across reconnect replays, keyed by tid

  const onEvent = (e) => {
    const ev = JSON.parse(e.data);
    if (seen.has(ev.tid)) return;
    seen.add(ev.tid);
    render(ev);
  };
  es.addEventListener("fill", onEvent);
  es.addEventListener("settlement", onEvent);

  // fires on the 30-min lifetime cut and network drops alike
  es.onerror = () => { es.close(); setTimeout(connect, 1000 + Math.random() * 2000); };
}
connect();
```

Dedup by `tid` matters: after a reconnect the 10-event replay overlaps what you already have.

### Rendering tip

Events carry raw `#N` coins — resolve display names from [`GET /v1/markets/coin-labels`](/mute.sh/api/api-reference/markets.md#get-v1marketscoin-labels) (one cached call covers the whole universe) and logos from [`/v1/markets/logos`](/mute.sh/api/api-reference/markets.md#get-v1marketslogos). That's the complete recipe for a live activity feed UI: stream + two cached maps.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mute-sh.gitbook.io/mute.sh/api/api-reference/fills-and-activity.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
