# Realized and open PnL per token

`GET https://api.getchord.xyz/v1/portfolio/{wallet}/pnl`

Source: https://getchord.xyz/docs/api-reference/operations/walletpnl/

Average-cost PnL for one wallet from the tape: realized on sells, unrealized on what is still held at current prices, ROI, and the untracked balance that arrived by transfer (no cost basis, excluded from PnL). Cached with stale-while-revalidate (a day-old answer beats a $0 skeleton).

Portfolio routes answer an empty 200 shape rather than a 5xx when the tape read fails — treat an empty `tokens` list as "nothing yet" and retry later.

## Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `wallet` | path | yes | string |  |
| `chain` | query | no | `5042` · `4663` · `143` · `all` (default `all`) | One chain, or `all` to merge chains with a `byChain` breakdown. |

## Response 200

Example (captured from the live API):

```json
{
  "tokens": [
    {
      "token": "0xece5ca8bf9220718e5727754026757512212cb3c",
      "symbol": "ARGUS",
      "logo": "https://coin-images.coingecko.com/coins/images/102178392/large/argus-token.png?1789463380",
      "realizedUsd": 30462.864779627198,
      "unrealizedUsd": 11700.939232721703,
      "totalUsd": 42163.804012348905,
      "costRemaining": 1286.137220108177,
      "curValue": 12987.07645282988,
      "curAmount": 744055.9147763874,
      "avgCost": 0.0017285491514366933,
      "roiPct": 909.7737822825419,
      "untrackedAmount": 0,
      "untrackedValue": 0
    },
    {
      "token": "0x66927743a8a841ca09575a4ccdcd090c761adcec",
      "symbol": "HYCI",
      "logo": "https://ipfs.filebase.io/ipfs/bafybeiezh2g4uhqy2bzdq4elwkzek55q5ccs4gpyyki672a4i3olf3u224",
      "realizedUsd": 181.713005,
      "unrealizedUsd": 0,
      "totalUsd": 181.713005,
      "costRemaining": 0,
      "curValue": 0,
      "curAmount": 0,
      "avgCost": 0.000042576384935211256,
      "roiPct": null,
      "untrackedAmount": 0,
      "untrackedValue": 0
    }
  ],
  "realized": 30488.101882774274,
  "unrealized": 11700.939232721703,
  "total": 42189.04111549597,
  "updatedAt": 1789809277093
}
```

- **400**: Invalid parameters — `error` names the check that failed (`INVALID_PARAMS`, `BAD_ADDRESS`, `BAD_LIMIT`, `BAD_HOURS`, …).
