---
title: "Changelog"
description: "What shipped across the AGG platform and the @agg-build packages."
---

> **For AI agents:** the complete documentation index is at [llms.txt](/llms.txt). Append `.md` to any page URL for its markdown version.

{/*
  AUTO-MANAGED — do not edit by hand.
  Version entries come from the per-package CHANGELOG.md files (written by
  Changesets). Dated weekly entries come from the changelog-digest workflow.
  Regenerate the version entries with: pnpm --filter docs generate:changelog
*/}

<Note>
  Weekly entries cover everything that shipped across the platform, including
  API and data-pipeline work. Version entries are the published
  `@agg-build` packages — those four are version-linked, so a release usually
  bumps them together, and the tags show which ones shipped.
  [Subscribe via RSS](/feed.xml).
</Note>

<Update label="2026-08-16 · v4.0.1" tags={["Patch", "sdk", "hooks"]}>

- Fix READMEs left stale by v4.

  Both packages still documented `quoteManaged` / `useQuoteManaged`, which were
  removed in v4 — the npm pages described methods that no longer exist. Replaced
  with the `getSmartRoute()` → `executeManaged()` flow (`useSmartRoute` →
  `useExecuteManaged` in React) and a note explaining the removal.

  The SDK's "Peer dependencies" section also claimed the package "bundles its own
  clients for `viem`, `ethers@5`, `@polymarket/clob-client` and
  `@polymarket/builder-signing-sdk`". That was never accurate — those were declared
  as runtime dependencies but no code path imported them, and none were bundled.
  It now states the truth: zero runtime dependencies, `node:crypto` the only
  imported module, bring your own signer.

  Also documents `AggApiError` / `isAggApiError`, added in v4 but missing from the
  exports table.

</Update>

<Update label="2026-08-16 · v4.0.0" tags={["Major", "sdk", "hooks", "ui", "auth"]}>

- **sdk, hooks:** Remove `quoteManaged` and `useQuoteManaged`, along with the `QuoteManagedParams`,
  `QuoteManagedResponse`, `QuoteManagedStep`, `QuoteManagedSplit` and
  `UseQuoteManagedOptions` types.

  Their endpoint, `POST /execution/quote`, does not exist on the API — the call has
  only ever returned 404, so no working integration can depend on it. Nothing in
  the SDK, hooks, UI library or demo app used them.

  To quote and fill a managed trade:

  ```ts
  const route = await client.getSmartRoute({ venueMarketOutcomeId, side, amount });
  await client.executeManaged({ quoteId: route.quoteId });
  ```

  The React equivalents are `useSmartRoute` and `useExecuteManaged`.
- **sdk:** Export `AggApiError` and `isAggApiError`. Every non-2xx API response has
  always been thrown with `status`, `code`, `retryable` and `errors` attached,
  but the thrown value was an untyped `Error`, so consumers had no way to reach
  those fields without matching on message text. The class and type guard are
  now exported; runtime behaviour is unchanged.
- **sdk:** Remove four unused runtime dependencies (`ethers`, `viem`,
  `@polymarket/clob-client`, `@polymarket/builder-signing-sdk`). None were
  imported by any code path — the SDK's only external import is `node:crypto`.
  This cuts roughly 65 MB from a fresh install and removes the corresponding
  bundler traversal, which was the single largest install-size contributor for
  React Native consumers.

</Update>

<Update label="2026-08-12 · v3.0.0" tags={["Major", "sdk", "hooks", "ui", "auth"]}>

- **sdk, hooks:** Remove `yesPrice` from `sortBy` on `listVenueMarkets` / `useVenueMarkets`. The
  cross-event browse sort by price had no consumer and its dedicated index was
  one of the largest on the table. Markets listed under an event still order by
  price where the event's structure calls for it, and the
  `minYesPrice`/`maxYesPrice` filters are unchanged. Callers passing
  `sortBy: "yesPrice"` should drop the option.

</Update>

<Update label="2026-08-11 · v2.9.0" tags={["Minor", "sdk"]}>

- Add display metadata to execution status steps: `orderIds`, `kind`, `groupId`, `groupStatus`, `label`, and `bridge` details, so clients can render per-leg execution progress without classifying raw DAG step types.
- Add `getVenueGeoPolicy()` — returns the per-venue blocked-country lists (ISO 3166-1 alpha-2) from `GET /app/venue-geo-policy`. This is the raw venue policy, not per-user eligibility; keep using the quote's `warnings` array to gate a fill.

</Update>

<Update label="2026-08-08 · v2.8.2" tags={["Patch", "sdk"]}>

- Add the missing `slippage` field to `SmartRouteResponse`.

  The API has always returned route slippage metrics on the smart-route response
  (`SmartRouteResponseTB.slippage` in the contract: `vwap`, `refMidpoint`,
  `slippage`, `slippageBps`), but the SDK's hand-mirrored interface never
  declared it. `@agg-build/hooks` reads `slippage.slippageBps` to flag thin
  liquidity, so that code — and its test — could not typecheck against the
  published type.

  Purely additive: the field is optional, so no existing consumer changes
  behaviour. The new `SmartRouteSlippage` interface is exported alongside it.

</Update>

<Update label="2026-08-07 · v2.8.1" tags={["Patch", "sdk"]}>

- Widen `WithdrawalSourceTokenSymbol` to include `USD1`. BNB USD1 (Myriad settlement
  inventory) can now fund a withdrawal, so it can appear in a withdrawal's `sources[]`.
  It is a source-only token — `WithdrawTokenSymbol` (the request/destination union) is
  unchanged, same as `pUSD`.

</Update>

<Update label="2026-08-06 · v2.8.0" tags={["Minor", "hooks", "ui"]}>

- Add `config.formatting.formatPrice` so partners can override how prices render.

  `formatPercent` already governed probability rendering on discovery surfaces, but every
  cents surface formatted prices with a hardcoded formatter. Partners using a non-percentage
  odds convention (decimal, fractional, moneyline) ended up with converted probabilities on
  discovery pages and unconverted cents everywhere else.

  `formatPrice` receives the same `0..1` probability as `formatPercent` and now governs the
  order book, event page outcome chips, place-order, and positions. Set both to the same
  function to apply one odds convention app-wide.

  The positions view model also honors `formatCurrency`, which it previously ignored.

  `formatPrice` is optional and unset by default, so every surface keeps its current
  rendering until a partner opts in. The order book spread and position PnL percentages stay
  on the built-in formatters by design — neither is a price.

</Update>

<Update label="2026-08-03 · v2.7.3" tags={["Patch", "ui"]}>

- Scope the order-book view for a selected outcome to that market's own matched set. The label fallback in `collectEligibleVenueOutcomes` no longer merges same-label outcomes from other markets that are on the opposite semantic side: a second same-venue market with a different question (a decomposed per-team sibling leg or a same-family total) and markets of a different framing shape (bare Yes/No leg vs team-titled single) are excluded when the user's exact outcome is known. Fixes the unmatched kalshi moneyline leg's No view showing polymarket rows the router can never fill on, and the crossed book / negative spread produced by merging opposite-side books.

</Update>

<Update label="2026-08-02 · v2.7.2" tags={["Patch", "hooks", "ui"]}>

- Event detail page: load every market instead of only the first page of 20.
  `useVenueMarkets` gains a `fetchAll` option that eagerly fetches remaining
  cursor pages until exhausted; `MarketDetailsList` and `useEnrichedVenueEvent`
  now use it with a 100-row page size, so events with many markets (e.g. 80+
  open markets) render their full market list instead of a silently truncated
  one.
- **ui:** Sports moneyline card: when a bare Yes/No leg and a cross-venue titled single
  collide on one aggKey (venue mis-keys a leg with the event base), keep the
  titled single — it renders one pill per team and carries the cluster —
  instead of first-wins evicting it.

</Update>

<Update label="2026-08-02 · v2.7.1" tags={["Patch", "ui"]}>

- Sports game-detail page: fix period tab ordering and add a sport-aware gate
  so a market never surfaces a nonsense tab for its sport. first_N_innings tabs
  now sort together, numerically by N (5 Innings no longer sorts before
  3 Innings). A period family implausible for the events sport (e.g. a Sets
  period on a baseball event) demotes to the Other tab instead of rendering its
  own tab, closing the gap left by an upstream Rust classification fix. The
  gate fails open: unknown or unlisted sports keep every existing tab.

</Update>

<Update label="2026-08-01 · v2.7.0" tags={["Minor", "hooks", "ui"]}>

- Sports game-detail tabs are now derived from the game's own markets instead of a
  fixed, soccer-shaped list. A baseball game renders Game Lines / 5 Innings / Home
  Runs / Strikeouts rather than Game Lines / Halves / Other.

  Three tab kinds are derived per game: **Game Lines** (full-game moneyline,
  spreads and totals, plus team props and specials such as the first-inning-run
  and extra-innings markets), **one tab per period family that has lines** (1h and
  2h collapse into a single Halves tab as before, while first_5_innings reads as 5
  Innings), and **one tab per player-prop stat**, labelled from the market subtype.

  Soccer Corners / Goals / Assists / Shots tabs are unchanged and still resolve
  their labels through the existing cornersTab / goalsTab / assistsTab / shotsTab
  ui-config keys, so partner overrides keep working. Three new overridable label
  keys are added: quartersTab, setsTab and playerPropsTab.

  The Game Lines tab no longer filters to regular time. Period-scoped markets now
  have their own tabs, and that filter had been hiding the period-scoped game props
  which belong on Game Lines.
- **ui:** Sports moneyline card: drop decomposed per-team legs as a set once their merged
  single is present, instead of only the legs carrying a match edge. The matcher
  routinely pairs just some of a game's legs, which left an orphan leg beside the
  anchor and still rendered the whole matchup question as a pill.
- **ui:** Trade panel: stop presenting an unaffordable primary route as a dead end when
  the same quote carries an executable solo. Solo route cards with their own
  quoteId no longer inherit the primary's `insufficient_balance` status/error,
  and the default card selection prefers the executable solo when the primary is
  blocked on funding — a Kalshi-funded user with no on-chain balance now lands on
  a submittable Kalshi route instead of a blocking "Insufficient balance" alert.
  Quotes where nothing is executable still block exactly as before.

</Update>

<Update label="2026-08-01 · v2.6.0" tags={["Minor", "hooks", "ui"]}>

- Sports game-detail tabs are now derived from the game's own markets instead of a
  fixed, soccer-shaped list. A baseball game renders Game Lines / 5 Innings / Home
  Runs / Strikeouts rather than Game Lines / Halves / Other.

  Three tab kinds are derived per game: **Game Lines** (full-game moneyline,
  spreads and totals, plus team props and specials such as the first-inning-run
  and extra-innings markets), **one tab per period family that has lines** (1h and
  2h collapse into a single Halves tab as before, while first_5_innings reads as 5
  Innings), and **one tab per player-prop stat**, labelled from the market subtype.

  Soccer Corners / Goals / Assists / Shots tabs are unchanged and still resolve
  their labels through the existing cornersTab / goalsTab / assistsTab / shotsTab
  ui-config keys, so partner overrides keep working. Three new overridable label
  keys are added: quartersTab, setsTab and playerPropsTab.

  The Game Lines tab no longer filters to regular time. Period-scoped markets now
  have their own tabs, and that filter had been hiding the period-scoped game props
  which belong on Game Lines.
- **ui:** Sports moneyline card: drop decomposed per-team legs as a set once their merged
  single is present, instead of only the legs carrying a match edge. The matcher
  routinely pairs just some of a game's legs, which left an orphan leg beside the
  anchor and still rendered the whole matchup question as a pill.

</Update>

<Update label="2026-07-31 · v2.5.3" tags={["Patch", "ui"]}>

- Sports moneyline card: render one pill per team when a venue's decomposed
  per-team legs and their merged cross-venue single are both in scope. Opening
  the leg venue's own event (e.g. kalshi's side of an MLB game) previously showed
  the merged anchor as an extra pill labelled with the whole matchup question.

</Update>

<Update label="2026-07-30 · v2.5.2" tags={["Patch", "ui"]}>

- Show every quoted venue in Smart Routing, not just the fundable ones. A solo
  venue whose own funding lane was short came back without an executable quote id
  and was dropped from the comparison list — so when an off-chain venue won the
  route (which keeps the overall quote `ok`), the alternative venue vanished from
  the panel entirely. The card now renders with its payout for comparison; the
  panel's existing Deposit / Add funds CTA remains the funding signal.

</Update>

<Update label="2026-07-28 · v2.5.1" tags={["Patch", "sdk", "hooks"]}>

- Add `isVenueExecutable` venue predicate (`@agg/common`) for gating per-venue order-execution eligibility, distinct from `isVenueActive` (compile-time) and `isVenueDataVisible` (data display).

</Update>

<Update label="2026-07-27" tags={["Weekly"]}>

### Changed

- Markets listed under an event are ordered more sensibly. Sets of competing candidates now sort by odds, and events whose legs are labelled by month sort chronologically instead of falling back to a shared settlement date.
- Limitless recurring short-window crypto markets now appear as soon as the venue publishes the next slot, ahead of the window opening, instead of showing up part-way through it. They arrive with `status` of `unopened` and only become tradable once the window starts.

### Fixed

- Orders and transfers no longer fail with invalid- or insufficient-balance errors in two cases: Limitless positions reported more shares than the wallet could actually sell, and BNB transfers were quoted against a larger amount than the one that landed in the wallet.
- Polymarket deposit wallets now resolve to the address the venue actually deployed. Funding and orders were being pointed at a predicted address that no longer exists on chain.
- Activity now lists only deposits a user actually made. Internal settlement and bridge transfers arriving in a managed wallet were being reported as incoming deposits.
- Polymarket events that were missing some of their markets, and quiet markets whose prices had stopped updating, now stay current.
- Markets Polymarket has shelved no longer show as open and tradable, and events that have finished report a `volume24hr` of `0` rather than a frozen figure.
- Full settlement rules are returned for every venue on a matched market instead of just one of them, and Limitless grouped markets now carry their own rules text.
- Search and orderbook reads stay fast and reliable under heavy load. Both previously slowed to several seconds or failed outright when traffic was high.

</Update>

<Update label="2026-07-24 · v2.5.0" tags={["Minor", "sdk"]}>

- Add `bookQuality` to position responses (`OutcomePosition`, `VenuePositionBalance`).

  Positions are marked at the price the held size could actually be closed at,
  by walking the venue's resting book. When a venue's book is degenerate — a
  handful of contracts of real bid behind a stub ladder — that mark collapses,
  but `priceSource` still reports `"orderbook"` because the walk did fill.
  Nothing in the response distinguished that from a healthy fill.

  `bookQuality` carries the engine's existing `BookQuality` verdict
  (`healthy` / `wide_spread` / `bid_only` / `ask_only` / `endpoint_stub` /
  `crossed` / `empty`) for the worst book across the position's legs, so
  clients can label a low-confidence mark instead of rendering it as a market
  price. Values are unchanged — this adds a signal, it does not re-mark.

  Read `priceSource` first: `bookQuality` only qualifies book-derived marks, and
  a `settled` position reports `empty` because it consults no book.

</Update>

<Update label="2026-07-23 · v2.4.9" tags={["Patch", "ui"]}>

- Fix Tailwind utilities resolving theme tokens at `:root` instead of at the element.

  The `@theme` block is now `@theme inline`, so `.bg-agg-primary` & friends emit
  `var(--agg-color-primary)` directly rather than a `--color-agg-*` alias bound at `:root`. Two
  consequences of the old form are fixed:
  - **Dark mode.** `:root` never matches `.dark .agg-root:not(.light)`, so every utility resolved
    against the light defaults regardless of theme — `.bg-agg-primary` rendered `#536dfe` and
    `.text-agg-foreground` rendered `#020205` on dark surfaces.
  - **Consumer theming.** Overrides scoped to `.agg-root` (including Partner Theme Studio's exported
    CSS) never reached any utility class.

  Apps that worked around this by re-declaring the palette at `:root` can drop that block.

</Update>

<Update label="2026-07-21 · v2.4.8" tags={["Patch", "auth"]}>

- Surface auth-callback failures as a toast. Account linking (and sign-in) completes on the OAuth redirect-return page, detached from the UI that started it — so when `linkAccountConfirm` rejects (e.g. HTTP 409 `already_linked_elsewhere` when the provider identity is already linked to a different user) the error only landed silently in `AggAuthProvider`'s error state and the user saw nothing. `AggAuthProvider` now toasts the callback error (when a toast provider is mounted) with a readable message — `already_linked_elsewhere` → "That account is already linked to a different user." — titled for linking vs sign-in based on whether a `link_confirm_token` is present.

</Update>

<Update label="2026-07-21 · v2.4.7" tags={["Patch", "sdk"]}>

- Fix `client.linkAccountConfirm()` 401'ing with "Missing Authorization header". Confirm runs on the OAuth redirect-return page, where the full-page reload has wiped the in-memory access token (tokens are never persisted). The request therefore went out with no `Authorization` header, and `request()`'s 401-refresh-retry is gated on an existing token so it couldn't recover — so account linking failed at the final step. `linkAccountConfirm()` now mints a fresh access token from the refresh cookie/token (deduped) before the request when the in-memory token is absent; if the session is genuinely gone the refresh throws and the caller surfaces it.

</Update>

<Update label="2026-07-21 · v2.4.6" tags={["Patch", "sdk", "hooks", "ui"]}>

- Complete the ProfileModal account-linking flow. The initial fix (#2503) switched ProfileModal's connect buttons to `client.linkAccount()`, but the rest of the round-trip was missing — this finishes it:
  - **`@agg-build/sdk`** — `client.linkAccount()` now sends `credentials: "include"` in the default bearer delivery mode. Without it the same-origin link-proof cookie the server sets on `/users/me/link-account/start` was dropped on the cross-origin response, so the OAuth link callback rejected every link with `link_proof_invalid`.
  - **`@agg-build/hooks`** — `handleAuthCallback` (the shared callback handler auto-run by `@agg-build/auth`'s `AggAuthProvider` and `useAggAuthCallback`) now detects the `link_confirm_token` the provider callback returns, calls `client.linkAccountConfirm()`, refreshes the user, and strips the token from the URL. Previously nothing consumed the token and the link silently never persisted. A collision (identity already linked to a different principal) surfaces as the callback error (HTTP 409); `already_linked_same` resolves idempotently.
  - **`@agg-build/ui`** — email linking (magic link, no redirect) now shows a "check your inbox" success toast so the click has visible feedback.

</Update>

<Update label="2026-07-21 · v2.4.5" tags={["Patch", "ui"]}>

- Fix ProfileModal social connect/disconnect. Connect now links the provider to the already-signed-in principal via `client.linkAccount()` (`POST /users/me/link-account/start`) instead of starting a fresh sign-in via `startAuth()` (`POST /auth/start`), which could not attach to the current user and caused a competing double-redirect. Disconnect (and connect) calls are now guarded and surface the API error (e.g. "Cannot disconnect the only linked auth provider") through the modal's toast instead of escaping as an unhandled promise rejection with no user feedback.

</Update>

<Update label="2026-07-14 · v2.4.4" tags={["Patch", "hooks"]}>

- Poll the venue-event query while a market lingers "open" past its endDate, so short-cadence markets (e.g. Kalshi 15-min BTC) transition to their resolved state instead of rendering a stale open market with no orderbooks (SNA-3047). endDate only triggers refetches — server status stays authoritative, so venues with inaccurate endDates can't disable trading.

</Update>

<Update label="2026-07-13 · v2.4.3" tags={["Patch", "ui"]}>

- Update settlement differences UI behavior

</Update>

<Update label="2026-07-11 · v2.4.2" tags={["Patch", "ui"]}>

- Stop the combined-moneyline card from rendering unmerged cross-venue duplicates of one market as two identical pills ("Match Winner" ×2 showing the same Yes price twice). When per-leg labels aren't distinct, the card falls back to the standard single-market rendering with team-title pills (SNA-3028, esports).

</Update>

<Update label="2026-07-10 · v2.4.1" tags={["Patch", "ui"]}>

- Render "Team to Advance" in the Game Lines tab, above the Moneyline (Polymarket parity). Knockout advance markets are primary game lines (multi-million volume) and were buried in Other; for a venue whose only market is the advance single (hyperliquid) this is what makes Game Lines exist at all. One card per game, anchored by the 2-outcome single with team-name pills (SNA-3028).

</Update>

<Update label="2026-07-10 · v2.4.0" tags={["Minor", "ui"]}>

- The Search primitive now requests `status: ["open"]` so open-only filtering happens server-side: pages arrive full of tradeable results and pagination is honest, instead of fetching all statuses and emptying resolved-heavy pages client-side (which rendered "No markets found" for queries like "5m btc" whose top results are recurring-series history).

</Update>

<Update label="2026-07-10 · v2.3.0" tags={["Minor", "sdk", "hooks", "ui"]}>

- **sdk, hooks:** Add an optional `status` filter to search: `client.search({ status: ["open"] })`, `useSearch({ status: ["open"] })`, and `useMarketSearch({ status: ["open"] })` return only markets/events in the given statuses. Pass `["open"]` for tradeable-only results — without it, recurring series (e.g. 5-minute up/down markets) can fill a page with resolved history, which a UI that hides non-open rows renders as an empty result.
- **ui:** Give whole-match totals a clean unit-based title ("Total Goals" / "Total Corners" / "Total Rounds") derived from the group's stat, instead of a raw venue question that produced labels like "Reg Time: Over 0.5 goals scored Totals" when a kalshi market anchored the group (SNA-3028). Per-team totals keep their subject ("Argentina Totals").

</Update>

<Update label="2026-07-10 · v2.2.4" tags={["Patch", "ui"]}>

- Show consistent team names on sports spread outcome pills (`{Favored} −X` / `{Dog} +X`) regardless of which venue anchors the ladder stop. A kalshi/limitless anchor stores `Yes`/`No` labels; the team names are now borrowed from the cross-venue twins (poly/predict) at the same signed line, falling back to `Yes`/`No` only when no venue carries a team title (SNA-3028).

</Update>

<Update label="2026-07-10 · v2.2.3" tags={["Patch", "ui"]}>

- Raise the sports event per-tab market fetch page size from 20 to 100 (the API max), so a prop-heavy tab like "Other" loads in 1–3 requests instead of ~15.
- Render sports spreads as a single symmetric ladder (home ← center → away) like Polymarket, instead of two same-titled "Spreads" cards. Both favored-side families (`…_sp_arg` / `…_sp_che`) now collapse into one spread group, and the ladder lays them on a signed magnitude axis with the home/first team anchoring the negative side (SNA-3028).

</Update>

<Update label="2026-07-10 · v2.2.2" tags={["Patch", "ui"]}>

- Group sports spread/total ladders by the aggKey line-family instead of the market question, so the same total (e.g. match total O/U) no longer fragments into separate cards across venues that phrase it differently (SNA-3028).

</Update>

<Update label="2026-07-08 · v2.2.1" tags={["Patch", "sdk", "hooks"]}>

- Clarify the id vocabulary across the WS surface and surface resolved-market status on `/midpoints`.
  - `useMarketOrderbook` now accepts `venueMarketOutcomeId` (the `outcomes[].id` from REST market responses); the old `marketId` option keeps working but is deprecated — it has always carried a venueMarketOutcomeId, not a venueMarketId.
  - SDK `onSnapshot`/`onDelta` callback parameters are renamed `outcomeId` (type-level only, no runtime change).
  - `subscribed`/`unsubscribed` confirmations on the arb channel now also echo the ids under `marketIds` (arb subscriptions are keyed by marketIds); the misleading `outcomeIds` mirror stays for backwards compatibility.
  - The gateway's `Snapshot unavailable for <id>` error now explains that orderbook subscriptions take venueMarketOutcomeIds, not venueMarketIds.
  - `GET /midpoints` entries now carry `marketStatus`, and resolved markets return null prices plus a structured `error` (`code: "market_resolved"`) instead of a stale settled-market mark; unknown ids get `code: "market_not_found"`.

</Update>

<Update label="2026-07-07 · v2.2.0" tags={["Minor", "sdk", "hooks", "ui"]}>

- Discovery responses no longer carry outcome prices. `GET /venue-events`,
  `GET /venue-events/:id`, and `GET /venue-markets` (and `/search`, which shares
  the same shapes) stop returning `venueMarketOutcomes[].price` — including on
  `matchedVenueMarkets[]` siblings. The `VenueMarketOutcome.price` type is now
  optional and deprecated. Fetch live prices from `GET /midpoints` (or the
  `useMidpoints` / `useViewportMidpoints` / live WS hooks), keyed by
  `venueMarketOutcomeId`. UI components already prefer live midpoints; the static
  `price` was only a pre-live seed and is now ignored when absent.

</Update>

<Update label="2026-07-05 · v2.1.5" tags={["Patch", "ui"]}>

- Sports detail page: honor the documented open period grammar (`set_N`, `map_N`,
  `game_N`, `period_N`, `inning_N`, `first_N_innings`) instead of collapsing those
  markets into the "Other" period bucket; treat `match` as full-game scope so
  whole-match markets stay in Game Lines; stop parsing the opaque `aggKey` for the
  league label (categories are the only label source).

</Update>

<Update label="2026-07-03 · v2.1.4" tags={["Patch", "ui"]}>

- Fold cross-venue moneyline legs into the 3-way Moneyline card regardless of which venue anchors the merged representative: `isBinarySportsMoneylineMarket` now also recognizes a leg by its deterministic `_ml_` aggKey (e.g. a kalshi-anchored "Reg Time: Brazil" with `marketSubtype=null`), so no leg drops out as a standalone row. Mis-tagged props stay excluded (they are never `_ml_`-keyed).

</Update>

<Update label="2026-07-02 · v2.1.3" tags={["Patch", "sdk", "hooks", "ui"]}>

- Add a `context: "list" | "detail"` option to `getVenueMarkets` / `useVenueMarkets` and pass `context: "list"` from the event tile's market-scroll query.

  On list/tile surfaces, axis and dates events now sort their markets by lifetime volume (biggest market first) for both the embedded top-3 and the scroll-loaded tail, while the detail page keeps its structured order (threshold/date ascending). `candidate`/`sport` events are unchanged.

</Update>

<Update label="2026-06-23 · v2.1.2" tags={["Patch", "sdk", "hooks", "ui", "auth"]}>

- Improve live trading and resolved-market handling across the AGG React packages.
  - `@agg-build/hooks`
    - invalidate and optimistically refresh cached market, balance, position, and activity data when `market_resolved` WebSocket events arrive
    - export venue-attributed live best-price candidate helpers/hooks so UI surfaces can keep the displayed venue logo aligned with the freshest live price
  - `@agg-build/ui`
    - add shared claim-winnings and resolved-market claim hooks for resolved positions
    - show the new resolved-market earnings/claim state in the event market flow
    - add `onBeforePrimaryAction` so partners can run a pre-submit gate before normal order execution
    - keep market detail outcome prices and venue logos in sync with live best-price updates
  - `@agg-build/sdk`
    - no direct SDK source or API changes landed in this push
    - patch bump only to keep the linked public package versions aligned for release/publishing with the updated hooks and UI peers

</Update>

<Update label="2026-06-19 · v2.1.1" tags={["Patch", "hooks", "ui"]}>

- Add provider-level AGG UI trading execution mode config.

  `AggProvider` now accepts `config.trading.executionMode` so hosted UI surfaces can share a global live or paper trading mode without threading `executionMode` through every page or order panel. `PlaceOrder`, `HomePage`, `EventMarketPage`, and `UserProfilePage` use the configured mode by default while preserving explicit component-level overrides.

  The shared balance provider now also uses the configured paper mode, so `ConnectButton` header totals and `UserProfilePage` balance/positions value cards read paper balances instead of falling back to live-mode zeroes.

  Paper balances are labeled as Paper in the user profile network breakdown, use a shared paper-mode icon, and show a tooltip warning when the app is running with simulated paper funds.

</Update>

<Update label="2026-06-17 · v2.1.0" tags={["Minor", "sdk", "hooks", "ui"]}>

- Add safe midpoint batching for component-driven market pages.

  `AggClient.getMidpoints` now splits large `/midpoints` GET requests into smaller batches and merges the responses, defaulting to 75 venue market IDs per request to stay below common CDN URL limits. React hooks and UI components read the same default through `config.market.maxMidpointIdsPerRequest`, and direct hook/SDK callers can override the cap when needed.

</Update>

<Update label="2026-06-12 · v2.0.0" tags={["Major", "sdk", "hooks", "ui", "auth"]}>

- **sdk, hooks:** Narrow recurrence filters to the documented public cadence enum and expose the full supported venue-event cadence list through `RECURRENCE_CADENCES`, including `PT10M`, `P1M`, and `P1Y`.

  Migration guidance: replace dynamic recurrence-catalog calls with the SDK `RECURRENCE_CADENCES` export or the OpenAPI enum. Pass the literal `"null"` only when filtering one-off venue events. `listRecurringCryptoMarkets` remains limited to deterministic crypto durations: `PT5M`, `PT15M`, `PT1H`, and `P1D`.

</Update>

<Update label="2026-06-12 · v1.3.0" tags={["Minor", "sdk", "hooks", "ui"]}>

- Frontend feature round-up since the last release: live arbitrage signals, nested category navigation, event-tile price gaps, paper-trading mode, and position/redeem fixes.
  - **Live arbitrage (`@agg-build/sdk`, `@agg-build/hooks`, `@agg-build/ui`)**
    - SDK added `subscribeArb` and `subscribeArbFeed`, with the supporting wire types (`WsArbMarketUpdate`, `WsArbFeedBatch`, `WsArbFeedEntry`), socket dispatch, reconnect, and refcount handling, and documented the new arb actions in the `WsClientMessage` union.
    - Hooks added `useMarketArb` (live per-market arb) and `useArbFeed` (event-level MAX rollup), exported with their `UseMarketArbResult` / `UseArbFeedResult` types.
    - UI brought back the arbitrage sort option and added event-list filters; event tiles and lists now surface arb-driven ordering.
  - **Nested categories (`@agg-build/hooks`, `@agg-build/ui`)**
    - Hooks added `useCategoryChildren` (with `UseCategoryChildrenOptions`) for fetching subcategories.
    - UI renders the category `displayName` on home tabs and event-list filters, supports nested subcategories, and `EventListProps` gained `onCategoryRootChange`. `HomePageCategory` now carries an optional `displayName`.
  - **Event-tile price gaps (`@agg-build/hooks`, `@agg-build/ui`)**
    - Hooks exported the `computePriceGaps` helper plus `MAX_PRICE_GAP_PCT` / `MIN_PRICE_GAP_PCT` and the `ComputePriceGapsOptions` / `PriceGapValue` types.
    - A new `enablePriceGap` feature flag and `priceGap` label gate compact price-gap signals on aggregated event tiles; tiles wait for midpoints before computing gaps to avoid flicker.
  - **Paper-trading mode (`@agg-build/sdk`, `@agg-build/hooks`, `@agg-build/ui`)**
    - SDK introduced the `ExecutionMode` (`"live" | "paper"`) type and threaded an optional `mode` through `ExecuteManagedParams`, smart-route params, positions/orders queries, and `ManagedBalancesParams`.
    - UI's place-order panel accepts an `executionMode` prop and reports the chosen `mode` back through `onPrimaryAction`.
  - **Positions, redeem, and claim fixes (`@agg-build/hooks`, `@agg-build/ui`)**
    - Hooks exported `invalidateUserClaimState` and now walk the active bucket when counting redeem-eligible positions; auto-settled HL winners are reported as redeemed rather than ineligible.
    - UI user-profile tabs trust server-provided position buckets, redeem payout renders from the 6-decimal `totalPayoutRaw` (no longer derived from `legs[0]` decimals), and a new partner-overridable `claim` label group powers claim lifecycle notifications.
  - **Withdrawals & misc (`@agg-build/sdk`, `@agg-build/ui`)**
    - SDK added the `WithdrawalSourceTokenSymbol` type to support pUSD withdrawal sources; `WithdrawManagedSourceItem.tokenSymbol` now accepts `pUSD`.
    - UI event-list skeletons can render the discovery sidebar (`withSidebar`), with refreshed event-tile coloring, volume sort, and updated `sort-volume-24hr` / `shield-trust` icons.

</Update>

<Update label="2026-06-05 · v1.2.13" tags={["Patch", "sdk"]}>

- Add `email: string | null` to the typed `accounts.created` webhook event payload so partners can read email addresses supplied by magic-link or OAuth sign-in.

</Update>

<Update label="2026-05-26 · v1.2.12" tags={["Patch", "hooks", "ui"]}>

- Expand the trading labels surface with 9 new partner-overridable keys
  for execution failure messaging (`sellNoOnchainPosition`,
  `venueQuoteUnfillable`, `venueMinOrderSize`, `sourceBalanceChanged`,
  `venueMarketResolved`, `dflowWalletUnverified`, `venueNoQuotePath`,
  `solanaBlockhashExpired`, `venueRateLimited`, `serviceBlockedOrder`),
  and wire matching patterns into `normalizePlaceOrderErrorMessage` so
  the SDK renders friendly copy for every `UserActionableStepError`
  reason code the trade-executor now emits.

  Also rewrites the venue-terminated pattern coverage to handle
  Limitless's `FAILED` / `UNMATCHED` settlement statuses with
  dedicated friendly copy (`"Order didn't settle on-chain"` and
  `"No liquidity matched your order at the quoted price"`), and extends
  the min-order-size pattern to recognize predict.fun's existing
  `predict_min_quantity` user-actionable copy.
- Centralize execution failure labels and clean up place-order error normalization for venue outages and expired submission deadlines.

</Update>

<Update label="2026-05-21 · v1.2.11" tags={["Patch", "sdk", "hooks", "ui", "auth"]}>

- Deposit & withdraw UX overhaul:
  - New `useWithdrawEstimate` hook surfaces per-route fee and ETA estimates before submit.
  - Refreshed deposit and withdraw flows, including new amount/method/success screens, transfer fee summary, and friendly error states.
  - `WithdrawManagedResponse` now exposes `completedAmountRaw`, and the WS `WithdrawalLifecycleEvent` includes `requestedAmountRaw` and `completedAmountRaw` so consumers can render the terminal settled amount.
  - New balance/activity invalidation helpers (`invalidateUserActivityQueries`, `invalidateUserMoneyState`, `userActivityQueryKeys`) exported from `@agg-build/hooks`.
  - User profile activity rows and balance cards updated with refined states; new `spinner` and `circle-xmark` icons; tooltip primitive tweaks.

</Update>

<Update label="2026-05-07 · v1.2.10" tags={["Patch", "ui"]}>

- Fix a bug in geo-blocking behavior for order splitting

</Update>

<Update label="2026-05-07 · v1.2.9" tags={["Patch", "ui"]}>

- UI updates for Positions tab and removed hardcoded colors

</Update>

<Update label="2026-05-06 · v1.2.8" tags={["Patch", "ui"]}>

- Added new prop in tooltip for gap and UI adjustments

</Update>

<Update label="2026-05-06 · v1.2.7" tags={["Patch", "ui"]}>

- Fix a bug in geo-blocking behavior for order splitting

</Update>

<Update label="2026-05-06 · v1.2.6" tags={["Patch", "ui"]}>

- UI updates in the withdraw modal and claim flow for design QA

</Update>

<Update label="2026-05-05 · v1.2.5" tags={["Patch", "ui"]}>

- Bug fix for nullable venueMarketOutcomeId

</Update>

<Update label="2026-05-05 · v1.2.4" tags={["Patch", "ui"]}>

- Bug fix for nullable venueMarketOutcomeId
- Update network chain logos to prediction-markets CDN paths; fix Solana missing from deposit modal network list

</Update>

<Update label="2026-05-05 · v1.2.3" tags={["Patch", "ui"]}>

- removed redundant div from venue selection

</Update>

<Update label="2026-05-04 · v1.2.2" tags={["Patch", "ui"]}>

- Sorting user positions

</Update>

<Update label="2026-05-04 · v1.2.1" tags={["Patch", "ui"]}>

- Market details UX updates

</Update>

<Update label="2026-05-04 · v1.2.0" tags={["Minor", "sdk", "hooks", "ui", "auth"]}>

- Added smart-route fee breakdown support across AGG packages.
  - `@agg-build/sdk` now includes optional `feeBreakdown` data on smart-route quote responses so integrators can display venue fees, bridge fees, execution gas, and total fees.
  - `@agg-build/hooks` adds `features.showFeesBreakdown` to UI config and new label keys for fees and updated positions table/status copy.
  - `@agg-build/ui` adds optional fee breakdown display in the place-order flow, updates route ordering to prioritize better executable value, improves mobile event-market trade opening from outcome selection, and upgrades positions UX (active/closed filtering, status/result badges, and claim-state handling).

  These changes are backward compatible and require no migration for existing integrations unless you want to enable the new fee breakdown UI (`showFeesBreakdown`).

</Update>

<Update label="2026-04-30 · v1.1.0" tags={["Minor", "ui"]}>

- Added xs size for icons and geo block updates for order

</Update>

<Update label="2026-04-30 · v1.0.2" tags={["Patch", "hooks", "ui", "auth"]}>

- Refresh published package metadata and fixes for the AGG SDK package stack.

  Updates:
  - @agg-build/hooks: fix midpoint price calculation in `useViewportMidpoints`; minor adjustments to UI-config labels and the `useWithdrawFlow` hook.
  - @agg-build/ui: settlement formatting refactor (new `settlement-text-renderer` + `settlement-text.utils`); `PlaceOrder` flow updates including default amount, sell-tab default, partially-filled state, best-price wiring, max label, and a sign-in-to-trade flow; refreshed typography variants; new `apps` and `circle-overlap` icons; custom `Select` migration for TBAs; connect-button view rewrite; event-list search/filter improvements.
  - @agg-build/auth: updates to the SIWE adapter and shared auth utils.

</Update>

<Update label="2026-04-28 · v1.0.1" tags={["Patch", "sdk", "hooks", "ui"]}>

- **sdk**: Add withdrawal lifecycle WebSocket support — new `WsWithdrawalLifecycleEvent` message type, `onWithdrawalLifecycle` SDK callback, and associated types (`WsWithdrawalLifecycleStatus`, `WsWithdrawalLegStatus`, `WsWithdrawalLifecycleLeg`).

  **hooks**: Add `useWithdrawFlow`, `useWithdrawalLifecycle`, and `useOnWithdrawalLifecycle` hooks with full withdrawal lifecycle tracking via WebSocket. Fix live outcome price fallback so REST midpoints surface when no WS midpoint exists. Improve `useMidpoints` to prefer the venue with the lower YES midpoint for better buyer pricing. Fix hooks package exports to use format-specific type declarations (`.d.mts` for ESM consumers).

  **ui**: Add wallet withdrawal flow — recipient address input, amount/token/network selection, confirmation step, and an order-style execution timeline showing per-leg bridge/transfer progress with live lifecycle status. Add `CopyButton` primitive. Show wallet address on card-payment pending step in the deposit flow. Surface best-price venue indicators in the event list, market details, and orderbook. Fix cluster-aware market deduplication to collapse cross-page duplicates.

</Update>

<Update label="2026-04-27 · v1.0.0" tags={["Major", "sdk", "hooks", "ui", "auth"]}>

- Initial v1.0.0 release of the AGG client libraries on npm under the `@agg-build` scope.

</Update>
