> 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/wallets-and-traders.md).

# Wallets & Traders

Everything keyed by a wallet address: portfolios, full profiles, skill analytics, and single-fill lookups. Three tiers of depth:

| Endpoint                         | Depth                                           | Built for                            |
| -------------------------------- | ----------------------------------------------- | ------------------------------------ |
| `GET /v1/portfolio/:user`        | positions + history summary                     | portfolio pages                      |
| `GET /v1/profile/:user/full`     | portfolio **plus** market labels + PnL history  | a complete trader page in one call   |
| `GET /v1/traders/…`              | skill analytics (smart-money rank, calibration) | leaderboards, "is this wallet good?" |
| `GET /v1/users/:user/fills/:tid` | one fill, fully contextualized                  | shareable trade-detail pages         |

Addresses are case-insensitive (lowercased server-side) and validated by format — a well-formed address that never traded returns a **`200` with zeroed totals and empty arrays**, not a `404`. Malformed → `400 Invalid address`.

## PnL numbers: read this first

Different endpoints intentionally aggregate different fill sets. For the *same wallet* you will see different "PnL" and "volume" figures — none are wrong, they answer different questions:

| Figure                     | Where                          | What it sums                                                                               |
| -------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------ |
| `total_pnl`                | portfolio, profile             | `closed_pnl` over **every** fill (trades, plumbing, settlements) — the all-in realized PnL |
| `settled_pnl`              | smart-money, settledOutcomes   | `closed_pnl` over **Settlement fills only** — what resolution paid/cost                    |
| edge's `settled_pnl`       | `/traders/:address/edge`       | settlement PnL over only the **scored subset** (see below) — can even differ in sign       |
| `total_volume` (portfolio) | `/v1/portfolio/:user`          | `px·sz` over **all** fills, settlement legs included                                       |
| `total_volume` (profile)   | `/v1/traders/:address/profile` | `px·sz` **excluding** settlement legs — pure trading volume                                |

***

## GET /v1/portfolio/:user

The wallet's whole book in one shot: lifetime totals, one row per market ever traded, the last 20 fills, the last 50 settlement legs. **No query params** — the response is the full history (a heavy market-maker returned 421 `by_market` rows / \~108 KB), so paginate/trim client-side.

```bash
curl -H "X-API-Key: $MUTE_KEY" \
  "https://api.mute.sh/v1/portfolio/0xaddc680878f96b93189f700d17f4a9bfcf80ff54"
```

```json
{
  "user": "0xaddc680878f96b93189f700d17f4a9bfcf80ff54",
  "totals": {
    "total_trades": 21700,
    "total_settlements": 128,
    "wins": 70,
    "losses": 58,
    "total_pnl": 263570.75,
    "total_volume": 3440108.75,
    "total_fees": 0,
    "markets_traded": 208
  },
  "by_market": [
    {
      "coin": "#7530",
      "total_trades": 13,
      "total_settlements": 0,
      "won_count": 0,
      "lost_count": 0,
      "total_volume": 1139.44,
      "total_pnl": 0,
      "total_fee": 0,
      "first_trade": "2026-07-05 07:57:26.076",
      "last_trade": "2026-07-05 08:13:14.297"
    }
  ],
  "recent_fills": [
    { "time": "…", "coin": "#7530", "side": "B", "dir": "Buy", "px": 0.59, "sz": 65, "closed_pnl": 0, "fee": 0 }
  ],
  "settlements": [
    { "time": "…", "coin": "#7441", "side": "A", "px": 1, "sz": 1000, "closed_pnl": 125.27 }
  ]
}
```

* `by_market` is one row per coin (not per outcome — a wallet trading both sides gets two rows), sorted by most recent trade, **unbounded**.
* `wins`/`losses` count settlement legs at `px=1`/`px=0`; `recent_fills` includes every `dir` type, so expect plumbing rows.
* All numeric fields are JSON numbers on the wire.

### GET /v1/portfolio/:user/pnl-history

Daily realized PnL with a running total — chart-ready equity curve. One row per calendar day that had at least one fill (quiet days are absent, not zero-filled). **No query params**: the full history comes back every time; `?days=`-style filters are silently ignored, so truncate client-side.

```json
{
  "user": "0xaddc…ff54",
  "data": [
    { "date": "2026-05-12", "daily_pnl": 8.67, "trades": 90, "wins": 0, "losses": 0, "cumulative_pnl": 8.67 },
    { "date": "2026-07-05", "daily_pnl": 4743.56, "trades": 17, "wins": 3, "losses": 0, "cumulative_pnl": 263570.75 }
  ]
}
```

The final `cumulative_pnl` equals the portfolio's `totals.total_pnl` exactly — same fill set, same math.

***

## GET /v1/profile/:user/full

The one-call trader page: everything `/v1/portfolio/:user` returns **plus** a resolved `label` on every `by_market` row (name, sides, class, underlying, `logo_url`) **plus** the full `pnl_history`. This replaces three round-trips and a client-side metadata join.

```json
{
  "user": "0xaddc…ff54",
  "totals": { "…": "same shape as portfolio" },
  "by_market": [
    {
      "coin": "#7530",
      "total_trades": 13,
      "total_volume": 1139.44,
      "label": {
        "name": "Recurring",
        "description": "class:priceBinary|underlying:BTC|expiry:20260706-0600|targetPrice:62731|period:1d",
        "side_a_name": "Yes",
        "side_b_name": "No",
        "market_class": "priceBinary",
        "underlying": "BTC",
        "logo_url": "https://app.hyperliquid.xyz/coins/BTC.svg"
      }
    }
  ],
  "recent_fills": ["…20 rows…"],
  "settlements": ["…50 rows…"],
  "pnl_history": ["…full daily history…"]
}
```

`label` is `null` for the rare coin with no metadata row yet. Fixed caps: `recent_fills` 20, `settlements` 50, `by_market`/`pnl_history` unbounded — none configurable.

***

## GET /v1/traders/smart-money

Wallets ranked by **risk-adjusted settlement PnL**: `score = settled_pnl / √settled_positions`, minimum sample size gated. The scoring formula is included in the response, so you can display it honestly.

| Query param  | Type | Default | Description                                             |
| ------------ | ---- | ------- | ------------------------------------------------------- |
| `min_sample` | int  | `10`    | minimum settled positions to qualify; clamped to 1–1000 |
| `limit`      | int  | `50`    | clamped to 1–200                                        |

Malformed values here are **clamped/defaulted, never `400`d** (`limit=abc` → 50; `0` counts as unset and resolves to the default, not the floor — only negative/out-of-range numbers clamp to the stated bounds).

```bash
curl -H "X-API-Key: $MUTE_KEY" "https://api.mute.sh/v1/traders/smart-money?limit=2"
```

```json
{
  "data": [
    {
      "rank": 1,
      "user": "0xb0026ca48937bd18c5941c05decab68b0fcced8a",
      "score": 29746.71,
      "settled_pnl": 154568.43,
      "settled_positions": 27,
      "wins": 22,
      "losses": 5,
      "win_rate": 0.815,
      "total_volume": 1655340.86,
      "roi": 0.093
    }
  ],
  "min_sample": 10,
  "limit": 50,
  "scoring": "score = total_settled_pnl / sqrt(settled_positions); ranked DESC; settled_positions >= min_sample required"
}
```

* The √-denominator rewards consistency: a 27-position/81% wallet outranks bigger absolute PnL earned over hundreds of coin-flips.
* `min_sample=1` intentionally surfaces one-hit wonders (one win, `win_rate: 1`, no risk discount) — keep the default for anything user-facing.
* `roi = settled_pnl / total_volume`, where `total_volume` comes from a periodically-updated rollup — it can lag live settlement numbers slightly and is `0` for wallets not yet rolled up.

**Caching:** `public, max-age=3600`.

***

## GET /v1/traders/:address/profile

The skill snapshot: pure trading volume (settlement legs excluded), all-in PnL, ROI, settlement win-rate, favorite categories/underlyings by volume, and a PnL percentile against the whole trader population.

```json
{
  "user": "0xfcecc2a54724cf0502eb7c916e2717ef76a510ed",
  "total_volume": 49557270.07,
  "total_trades": 47838,
  "total_pnl": 127225.57,
  "roi": 0.003,
  "win_rate": 0.245,
  "wins": 70,
  "losses": 216,
  "settled_positions": 286,
  "favorite_categories": [
    { "name": "sports", "volume": 44509230.09, "trades": 45678 }
  ],
  "favorite_underlyings": [
    { "name": "BTC", "volume": 6598.41, "trades": 70 }
  ],
  "pnl_percentile": 1
}
```

* The example above is a market maker, and the shape tells you: enormous volume, near-zero ROI, sub-25% settlement win rate. A directional-bettor profile looks the opposite (modest volume, high ROI). This endpoint is your MM-vs-bettor classifier.
* `pnl_percentile` is the fraction of all wallets with strictly lower lifetime PnL (`1` = top). **`null` means "not in the stats rollup yet"** (brand-new wallet), which is different from a true 0th percentile.
* `favorite_*` rank by non-settlement volume, top 10, excluding empty/`other` buckets.

**Caching:** `public, max-age=30`.

***

## GET /v1/traders/:address/edge

Calibration analysis: was the wallet's entry price a good probability estimate? For every settled position entered via a Buy, it compares average entry price against the realized outcome and produces a **Brier score** plus a 10-bucket calibration table.

```json
{
  "user": "0xaddc…ff54",
  "brier_score": 0.133,
  "scored_positions": 128,
  "win_rate": 0.547,
  "settled_pnl": 258903.4,
  "buckets": [
    { "bucket": "0-10", "positions": 7, "wins": 0, "win_rate": 0, "avg_entry_prob": 0.081, "settled_pnl": -2440.5 },
    { "bucket": "90-100", "positions": 7, "wins": 7, "win_rate": 1, "avg_entry_prob": 0.921, "settled_pnl": 968.41 }
  ],
  "mode": "full"
}
```

How to read it:

* **`brier_score`** = mean squared error between entry probability and outcome. `0.25` is the "always say 50%" baseline — **lower is better**; `0.133` is genuinely well-calibrated. `null` when nothing is scorable.
* **`buckets`** group positions by entry price decile. A calibrated trader's `win_rate` per bucket tracks `avg_entry_prob`; buckets only appear when they contain positions.
* **`scored_positions` can be smaller than the profile's `settled_positions`** — only positions with an opening Buy qualify. Market-maker flow (two-sided, short-entry) gets dropped: the MM wallet scores 211 of its 286 settled positions. Consequently edge's `settled_pnl` covers only the scored subset and **can differ in sign** from the wallet's overall PnL — don't present them interchangeably.
* `mode` is always `"full"` today.

**Caching:** `public, max-age=30`.

***

## GET /v1/users/:user/fills/:tid

One fill, fully contextualized — the endpoint behind shareable trade pages and OG cards. Takes the wallet plus the fill's `tid` (from any `/v1/fills` row or activity event) and returns three sections:

```bash
curl "https://api.mute.sh/v1/users/0xaddc…ff54/fills/671447444524168"
```

```json
{
  "fill": {
    "time": "2026-07-05 08:13:14.297",
    "coin": "#7530",
    "side": "B",
    "dir": "Buy",
    "px": 0.59,
    "sz": 65,
    "fee": 0,
    "fee_token": "+7530",
    "closed_pnl": 0,
    "crossed": true,
    "start_position": 1874,
    "oid": 487777587657,
    "tid": 671447444524168,
    "hash": "0xe9fa…",
    "builder": "",
    "builder_fee": 0
  },
  "meta": {
    "outcome_id": 753,
    "name": "Recurring",
    "market_class": "priceBinary",
    "underlying": "BTC",
    "target_price": 62731,
    "expiry": "20260706-0600",
    "is_settled": false,
    "settlement_px": -1,
    "settle_fraction": null,
    "settled_at": null
  },
  "settlement": null
}
```

* `fill` is the bet itself (settlement rows are excluded from matching, so a settlement `tid` can't masquerade as a bet).
* `meta` is the market context, derived from the coin — `null` only if metadata hasn't been indexed.
* `settlement` is **this user's own settlement fill** on that coin: `{ px, sz, closed_pnl, time }` where `px: 1` = won, `px: 0` = lost. `null` while the market is open — a `null` settlement with `meta.is_settled: false` renders as "position open".

**Caching is the status signal:** open bets return `Cache-Control: no-store`; settled bets return `max-age=86400, immutable` — once settled, the page can be cached forever.

**Errors:** malformed address/`tid` → `400`; valid-but-unknown `tid` → `404 Fill not found`. `tid` accepts 1–20 digits (real `tid`s exceed 10^12 routinely).

**Rate-limit note:** this route currently meters at the free anonymous bucket (10 req/min) regardless of key tier — it's built to be hit by public share-page renders, so cache the settled ones (the headers already tell you when that's safe) rather than fetching per-render.


---

# 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/wallets-and-traders.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.
