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

# Changelog - May 2-24, 2026

> Archived polynode API and SDK changes from May 2 through May 24, 2026.

[← Back to the current changelog](/changelog)

[Newer: May 25-31, 2026](/changelog-may-25-31-2026) · [Earlier: May 1, 2026 →](/changelog-may-1-2026)

## 2026-05-22 — V3 grouped trade total alias

Added `total_amount_usd` to v3 `group_by=order_hash` trade responses. It is an additive alias of `total_usd` / `amount_usd`, so clients that already use the v2 grouped trade field can read the same total field on v3.

Affected endpoints:

* `GET /v3/wallets/{address}/trades?group_by=order_hash`
* `GET /v3/trades?group_by=order_hash`

Existing fields are unchanged.

***

## 2026-05-22 — Builder metadata and filtered builder trades

Builder analytics now include public builder profile metadata on all builder endpoints:

* `GET /v3/builders`
* `GET /v3/builders/{code}`
* `GET /v3/builders/{code}/trades`

New additive fields:

* `builder_code`
* `builder_name`
* `builder_logo`
* `builder_verified`

`/v3/builders/{code}/trades` also now supports builder-specific filters for `token_id`, `condition_id`, `market_slug`, `event_slug`, `side=buy|sell`, `min_amount`, `after`, `before`, `limit`, and `offset`.

`category` and `tag_slug` filters are available with guardrails. Very broad category/tag requests return a structured `400` asking you to add `market_slug`, `condition_id`, `token_id`, or time bounds.

```bash theme={null}
curl "https://api.polynode.dev/v3/builders/0x4898df15.../trades?market_slug=dota2-tundra-xtreme-2026-05-22-game1&tag_slug=sports&limit=10"
```

Existing fields and existing pagination behavior are unchanged.

***

## 2026-05-18 — PnL methodology note

For users comparing our PnL numbers to what the Polymarket frontend displays: the two are computed differently and will diverge for wallets that hold a lot of settled-but-not-redeemed positions.

**Polymarket's `pnl`** (leaderboard, profile chart) is a **mark-to-market equity curve delta**: `equity(end_of_window) − equity(start_of_window)`. Resolved markets are booked into the curve at settlement, regardless of whether the wallet has called `redeemPositions`.

**Our `net_realized_pnl`** counts realized closes only — CLOB sells (the wallet sold their shares back) plus V2 adapter events (redemptions, merges, NRC conversions). Unrealized gains on settled-but-unredeemed positions stay in `unrealized_pnl`, not `net_realized_pnl`.

**Empirically verified** against PM's `/closed-positions[].realizedPnl` on a representative wallet: per-position realized matches PM within 1%. The "lifetime pnl" headline diverges by the value of settled-not-redeemed positions in the wallet.

`total_pnl` (= `net_realized_pnl + unrealized_pnl`) is the closer comparison to PM's curve delta — it includes both closed and still-open positions priced at current market.

***

## 2026-05-18 — New endpoint: wallet P\&L time series

Added `GET /v3/wallets/{address}/pnl/events` — returns realized P\&L bucketed by `hour`, `day`, `week`, or `month` so you can plot a wallet's P\&L over time without pulling every trade. Each bucket includes `realized_pnl`, a running `cumulative_pnl`, gross profit/loss, win/loss counts, and event count. Supports `?period=1d|7d|30d|1y` shortcuts or explicit `after` / `before` Unix-second timestamps.

Most full-history queries return sub-second.

Other quality-of-life:

* `?after` / `?before` outside the wallet's active window now correctly return zero buckets instead of an error.
* All `/v3/*` paths now accept an optional trailing slash (`/v3/positions/` is equivalent to `/v3/positions`).
* Unknown `/v3/*` paths return a structured 404 with a `hint` pointing to the docs, rather than HTML.
* Invalid `sort` and `order` values now return `400` with the list of valid options instead of silently falling back to a default — typos surface immediately.

### Doc / API parity pass (later same day)

Round 2 of the parity work — pure alignment between the API and the public reference, no breaking changes:

* **`/v3/markets/condition/{condition_id}/positions`** — response field names now match `/v3/markets/{token_id}/positions`. Was returning abbreviated keys (`amt`, `avgp`, `bought`, `rpnl`, `tid`); now returns the long, documented names (`amount`, `avg_price`, `total_bought`, `realized_pnl`, `token_id`). Old keys are gone — update any client code using them.
* **`/v3/resolutions`** — `payout_numerators` is now a JSON array of integers (e.g. `[0, 1]`), matching `/v3/conditions/{cid}`. Was returning quoted strings. `payout_denominator` is also an integer now.
* **`/v3/builders`, `/v3/tags`, `/v3/tokens/{token_id}`** — response envelopes now include `offset` and `limit` like every other list endpoint.
* **Param validation tightened** — invalid `?order=`, `?side=`, `?status=`, `?group_by=`, `?sort_by=` on trades / fees / resolutions / positions endpoints now return `400` with the valid-values list, instead of silently falling back to a default. Valid values still pass through unchanged.
* **Token price scale** — `/v3/markets/{token_id}/price.price` and `/v3/tokens/{token_id}.data[].price` are JSON numbers in USD (range `0`–`1`), not 6-decimal strings. Reference page text updated accordingly.

***

## 2026-05-16 — V3 API goes live + performance fixes

All `/v3/*` endpoints are now generally available (no longer "Coming Soon"). Several queries that timed out or ran slowly now return reliably and much faster:

* `/v3/wallets/{addr}/positions` — default sort no longer times out, returns in \<100ms
* `/v3/markets/slug/{slug}/trades` — fixed timeout, now \<100ms
* `/v3/tags/{slug}/leaderboard` — small/medium tags are now sub-second; tags larger than 4,000 markets return a structured "too large" hint pointing to the global leaderboard
* `/v3/tags/{slug}` — drops from 4.8s to \~1s
* `/v3/wallets/{addr}/trades` — drops from 2.3s to \~200ms

Tag slugs are now matched case-insensitively and accept URL-style hyphens: `/v3/tags/us-election/leaderboard` resolves to the stored tag `US Election`.

Several doc examples that previously showed a `columns/rows` envelope have been corrected to the `data: [{...}]` shape that the API actually returns.

***

## 2026-05-14 — SDK fix: deposit wallet deploy + approve

Fixed the deposit wallet (V2 / POLY\_1271) onboarding flow across all three SDKs. The relayer's `/submit` endpoint now requires builder authentication for WALLET-type submissions. All SDKs have been updated to include the required auth headers.

If you previously hit `401 invalid authorization` or `API key and signer mismatch` errors when deploying a deposit wallet or setting approvals, update to the latest SDK version:

```bash theme={null}
npm install polynode-sdk@0.10.7    # TypeScript
cargo update -p polynode            # Rust (0.13.4)
pip install polynode==0.10.4        # Python
```

`ensureReady()` handles the full flow automatically — deploy, approve, create credentials. If your wallet is already deployed, it skips to approvals. If approvals are already set, it skips to credentials.

***

## 2026-05-10 — Sort and group trades by order hash

`/v2/onchain/trades` now supports two new query parameters for working with limit order fills:

**`sort_by=order_hash`** — reorders the response so all fills from the same limit order are adjacent, sorted by time within each order. Every fill is still returned individually. No data is collapsed.

```bash theme={null}
curl "https://api.polynode.dev/v2/onchain/trades?wallet=0x...&sort_by=order_hash&limit=100" \
  -H "x-api-key: YOUR_KEY"
```

**`group_by=order_hash`** — aggregates all fills from the same limit order into a single row with `total_amount_usd`, `total_shares`, `avg_price` (VWAP), `fill_count`, time range (`first_fill_at` / `last_fill_at`), and a `tx_hashes` array.

```bash theme={null}
curl "https://api.polynode.dev/v2/onchain/trades?wallet=0x...&group_by=order_hash&limit=100" \
  -H "x-api-key: YOUR_KEY"
```

A single limit order can be filled across hundreds of transactions over hours or days. These parameters let you view that activity at either granularity.

***

## 2026-05-05 — Magic-link wallet EOA recovery in `/resolve`

`/v1/resolve` now returns the controlling EOA for Polymarket magic-link wallets — accounts created with email or social login. Previously these returned `eoa: null` because Polymarket's profile API does not expose the signer for this wallet type.

```json theme={null}
{
  "safe": "0x16cbe223607a6513ae76d1e3751c78e4eabc2704",
  "eoa": "0xbe5ba588ab7173b34efc0706b881794951014293",
  "username": "MRF",
  "type": "proxy"
}
```

**No code changes required.** The response shape is unchanged. The `eoa` field is now populated for the vast majority of `type: "proxy"` wallets. A small number may still return `eoa: null` where the EOA cannot be determined.

Repeat queries are sub-100ms.

***

## 2026-05-02 — Deposit wallet support

Polymarket is rolling out deposit wallets as a new account type for new users. This release adds full support across the API, all three SDKs, and the copy trading engine. **Existing integrations are fully backward compatible** — no code changes required unless you want to take advantage of the new features.

Read the full [Deposit Wallets guide](/guides/deposit-wallets) for details, code examples, and FAQ.

### What's new

**`/resolve` endpoint** — now returns a `type` field (`"safe"`, `"deposit_wallet"`, or `"proxy"`) in all responses. Resolves deposit wallets in both directions: wallet address to EOA and EOA to wallet address. Existing `safe`, `eoa`, and `username` fields unchanged.

```json theme={null}
{
  "safe": "0x8b60bf0f650bf7a0d93f10d72375b37de18f8c40",
  "eoa": "0xa60601a4d903af91855c52bfb3814f6ba342f201",
  "username": null,
  "type": "deposit_wallet"
}
```

**SDK — address derivation and detection** — `deriveDepositWalletAddress(eoa)` computes the deterministic deposit wallet address for any EOA. `detectWalletType()` and `ensureReady()` automatically detect whether an EOA has a Safe, proxy, or deposit wallet. Safe is checked first, so existing users keep their existing wallet type.

**SDK — order signing** — when `signatureType` is `POLY_1271` (3), the SDK wraps the EIP-712 signature using ERC-7739 TypedDataSign format automatically. `order()` / `signV2Order()` / `create_signed_order_v2()` detect the signature type from stored credentials and sign correctly. No code changes needed on your side.

**SDK — onboarding** — `ensureReady()` handles the full flow for deposit wallet users: derives the wallet, deploys via `WALLET-CREATE` if needed, and sets V2 approvals via a signed `WALLET` batch. Same one-call pattern as Safe wallets.

**Copy trading** — the copy trading engine generates the correct typed data for deposit wallet followers (`sig_type: 3`). Your signing code should use `signV2Order()` from the SDK.

### Install

```bash theme={null}
cargo add polynode@0.13.3        # Rust
npm install polynode-sdk@0.10.6  # TypeScript
pip install polynode==0.10.3     # Python
```

### Do I need to update?

* **If you only read data** (positions, trades, resolve): no changes needed. The `type` field is additive.
* **If you place orders via the SDK**: update to the versions above. Your code stays the same.
* **If you build order signatures yourself**: you need to implement ERC-7739 wrapping for `signatureType: 3`. See the [guide](/guides/deposit-wallets#how-poly_1271-signing-works).
