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

# Changelogs

> Release notes for the Zerion API covering new blockchain support, endpoint changes, documentation updates, and other feature and bug-fix announcements.

<Update label="October 1, 2026" description="Fewer duplicate share tokens" tags={["Change"]}>
  ## `no_filter` now leaves out more duplicate share-token rows

  With `filter[positions]=no_filter`, a share token such as an LP token, aToken or vault share is often left out as its own `wallet` row when a returned position carries it as `receipt`. So `no_filter` can return fewer rows than `only_simple` and `only_complex` combined.

  Some share tokens still appear twice. To count each holding once, see [Deduplicating share tokens](/recipes/defi-positions#deduplicating-share-tokens).

  `only_simple` and `only_complex` are unchanged. No field was added, removed, renamed or retyped.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/positions/`
  * `GET /v1/wallet-sets/positions/`
</Update>

<Update label="September 24, 2026" description="Receipt token quantity" tags={["Feature"]}>
  ## `receipt.quantity` on DeFi positions

  Wallet and wallet-set position responses now carry `receipt.quantity` on a receipt with `fungible_info`, such as an LP token or an ERC-4626 vault share. It has the same shape as `attributes.quantity`, and its `int` is the raw on-chain amount of the receipt token the wallet holds.

  The field is omitted when the amount is unavailable, zero or encrypted. Receipts with `nft_info` are unchanged and carry no quantity.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/positions/`
  * `GET /v1/wallet-sets/positions/`
</Update>

<Update label="September 23, 2026" description="Update subscription filters" tags={["Feature"]}>
  ## `PATCH /v1/tx-subscriptions/{subscription_id}/filters`

  Event filters on an existing subscription can now be replaced or cleared without recreating the subscription. Omit `filters` to leave the stored value unchanged, send `filters: null` to clear it, or send an object to replace it wholesale — a replacement is not merged with what was stored before, so a new object that omits a previously set condition drops that condition too. Returns `204` in every case, including a no-op.
</Update>

<Update label="September 22, 2026" description="Fungibles filters now fail closed" tags={["Breaking", "Change"]}>
  ## `GET /v1/fungibles/` refuses an empty filter value and an unknown chain

  Two filter behaviours on `GET /v1/fungibles/` that used to pass silently are now `400`.

  **A filter present with an empty value is refused.** `filter[search_query]=`, `filter[implementation_chain_id]=`, `filter[implementation_address]=`, `filter[fungible_implementations]=` and `sort=` were read as if the parameter had not been sent, so the request was answered with the unfiltered first page:

  ```
  GET /v1/fungibles/?filter[implementation_address]=
  ```

  That returned `200` with 100 assets. It now returns `400` with `address should be a valid EVM or Solana address`, the same error any other invalid address already produced. The published schemas already said as much — `filter[implementation_address]` has carried `minLength: 32` and `filter[search_query]` `minLength: 1` — so this enforces the documented contract rather than narrowing it. `filter[asset_class]` and `filter[fungible_ids]` already behaved this way.

  **A chain id that `GET /v1/chains/` does not list is refused.** `filter[implementation_chain_id]` was only checked for shape, so a numeric id (`4663`), a hexadecimal id (`0x1237`), an alias (`bsc` rather than `binance-smart-chain`) or a retired chain was forwarded to the search index verbatim and came back as `200` with an empty list — indistinguishable from a chain we simply hold no assets for:

  ```json theme={null}
  {
    "errors": [
      {
        "title": "Malformed parameter was sent",
        "detail": "chain 4663 does not support fungibles"
      }
    ]
  }
  ```

  This is the same rule `filter[chain_ids]` has followed on the wallet endpoints since September 18. A chain that `GET /v1/chains/` does list but that we hold no assets for is unaffected and still returns `200` with an empty list.

  **Not changed:** an unrecognised `filter[...]` key is still ignored rather than refused. `filter[address]=0x...`, for instance, has no effect and the request is served as if it were absent.
</Update>

<Update label="September 18, 2026" description="Unsupported chains now resolve to 404" tags={["Breaking", "Change"]}>
  ## `GET /v1/chains/{chain_id}` resolves only the chains we list

  `GET /v1/chains/{chain_id}` now returns `404` for any chain that `GET /v1/chains/` does not list:

  ```json theme={null}
  {
    "errors": [
      {
        "title": "Requested chain was not found",
        "detail": "You have requested chain which does not exist or is not supported by our platform"
      }
    ]
  }
  ```

  **Breaking change:** it previously returned `200` with every flag `false` for any of the \~1,500 chains in our internal chain registry, including chains the API has never served. `GET /v1/chains/moonbeam` returned `200` on 2026-08-31 and returns `404` today. If you treated a `200` as proof that a chain is usable, that check silently passed for chains we do not support; the `404`, or the `flags` on a listed chain, is now the answer. Nothing changed for a chain that `GET /v1/chains/` lists.

  `zero` (shut down 2026-08-07) and `degen` (sunset 2026-08-31) are part of this: they no longer appear in `GET /v1/chains/` and now resolve to `404`.

  **Also changed, not breaking.** When `filter[chain_ids]` names a chain the endpoint cannot serve, the `400` response now says which capability is missing — `chain bob does not support positions` instead of only reporting that the chain is not supported. The status code, the `title` (`Malformed parameter was sent`) and the response shape are unchanged, and the parameter descriptions on the affected endpoints now state which `flags` field each one gates on.
</Update>

<Update label="September 18, 2026" description="Per-capability chain support flags" tags={["Feature"]}>
  ## Chains now report which capabilities they support

  `GET /v1/chains/` and `GET /v1/chains/{chain_id}` return three new booleans in `flags`, alongside the existing `supports_trading`, `supports_sending` and `supports_bridge`:

  * `supports_transactions` — transaction history is indexed for this chain.
  * `supports_positions` — wallet positions (token balances and DeFi positions) are indexed for this chain.
  * `supports_nft_positions` — NFT positions and NFT collections are indexed for this chain.

  These are the same booleans the chain-filtered endpoints already gate on, so a chain that cannot serve a capability is now visible before you call. The transaction endpoints require `supports_transactions`, the position endpoints require `supports_positions`, the NFT position and collection endpoints require `supports_nft_positions`, and the chart, PnL and transaction-subscription endpoints require both `supports_transactions` and `supports_positions`. Naming a chain in `filter[chain_ids]` that lacks the capability the endpoint needs returns `400`.

  For example, `bob` is returned by `GET /v1/chains/` with `supports_transactions: true` and `supports_positions: false`. `GET /v1/wallets/{address}/transactions/?filter[chain_ids]=bob` returns `200`, while `GET /v1/wallets/{address}/positions/?filter[chain_ids]=bob` returns `400` with `chain bob does not support positions`. Until now the only way to learn that was to make the call; `supports_positions: false` is the advance warning.

  All six flags are always present on every chain. No existing field was removed, renamed or retyped.
</Update>

<Update label="September 16, 2026" description="Arc chain support" tags={["Feature"]}>
  ## Arc is now supported

  Arc is available across the Zerion API under the chain ID `arc`. Pass it wherever a chain is selected, such as `filter[chain_ids]` on the wallet endpoints or `filter[implementation_chain_id]` on `GET /v1/fungibles/`, and it is returned by `GET /v1/chains/` alongside the other mainnets.

  Supported on Arc:

  * Token balances and prices
  * Transaction history
  * Balance charts

  DeFi protocol positions and NFTs are not supported on Arc.

  Arc's native asset is USDC rather than a chain-specific gas token, so a wallet's native balance on Arc comes back as USDC.

  See [Supported blockchains](/supported-blockchains) for the full coverage matrix.
</Update>

<Update label="September 9, 2026" description="Endpoint descriptions rewritten for shareable links" tags={["Docs"]}>
  ## Endpoint reference pages now have their own page descriptions

  Every operation in the reference now carries a dedicated one-line page description, so sharing an endpoint URL in Slack, Telegram or a search result shows a readable summary instead of the first 1,500 characters of the endpoint docs.

  The endpoint descriptions themselves are 40% shorter. Guidance that was repeated on many endpoints now lives in one place and is linked from the endpoints that need it: [Resource IDs](/endpoints-and-schema#resource-ids) (was repeated on 24 endpoints), [Testnets](/supported-blockchains#testnets) (12), and [request URL length](/pagination-and-filtering#filtering) (8). The signature-verification walkthrough on `POST /v1/subscriptions/transactions/` now points at the [Webhooks guide](/webhooks), which carries Python and JavaScript examples in place of the Go example that was inlined in the spec with an expired certificate.

  Two corrections. The retry-until-`200` note has been removed from `GET /v1/wallets/{address}/positions/`, `GET /v1/wallets/{address}/portfolio/` and their wallet-set equivalents: those endpoints have no `202` response and never had one, so there was nothing to poll for. It stays on the NFT endpoints, which do return `202` while a new wallet is indexed. Separately, the portfolio endpoints now state that `filter[positions]` defaults to `only_simple`, so the totals exclude DeFi protocol positions unless you ask for them.

  No request or response behavior changed.
</Update>

<Update label="September 9, 2026" description="Encrypted quantity response schemas" tags={["Docs"]}>
  ## Encrypted quantities in positions and transfers

  The response schemas now define an optional `encrypted_quantity` object for v1 positions and transfers, and v2 transfers. Position receipts expose no quantity and therefore no encrypted quantity either. It contains a single `handle`: an opaque 32-byte ciphertext reference, encoded as `0x` followed by 64 lowercase hexadecimal digits.

  For clients enabled to receive encrypted values, the object's presence means the quantity is unknown. Required quantity fields use zero compatibility placeholders, and position or transfer values are `null`. These placeholders must not be interpreted as measured zero balances or used to calculate values. Public asset unit prices remain available. Ordinary responses omit `encrypted_quantity` and retain their existing format.
</Update>

<Update label="September 7, 2026" description="Subscription event filters" tags={["Feature"]}>
  ## Webhook subscriptions accept event filters

  A subscription can now carry `filters.exclude` to drop events before delivery, by transaction type, spam classification, protocol, or address. The field is optional, so existing subscriptions are unaffected.
</Update>

<Update label="September 7, 2026" description="Filter fungibles by asset class" tags={["Feature"]}>
  ## `GET /v1/fungibles/` can be filtered by `asset_class`

  Two new query parameters on the fungibles list, for organizations with the RWA classification add-on:

  * `filter[asset_class]` — keep only fungibles whose `asset_class` is one of the given values (comma-separated). Takes the same public vocabulary the attribute returns: `commodity`, `tokenized_stock`, `tokenized_treasury`, `stablecoin`, `other_financial`, `other_non_financial`, `unknown`.
  * `filter[has_asset_class]=true` — keep only classified fungibles, whatever the class. A dedicated filter rather than a wildcard value, because `asset_class` being absent is not a negative signal and the filter should not suggest otherwise; `false` is refused with `400`.

  ```
  GET /v1/fungibles/?filter[asset_class]=tokenized_stock&filter[implementation_chain_id]=solana&sort=-market_data.market_cap
  GET /v1/fungibles/?filter[has_asset_class]=true&page[size]=100
  ```

  Both combine with `filter[implementation_chain_id]`, a text `filter[search_query]`, `sort`, and cursor pagination. They are mutually exclusive with each other and are refused with `400` alongside `filter[fungible_ids]`, `filter[fungible_implementations]`, `filter[implementation_address]`, or an address passed as `filter[search_query]` — those paths look fungibles up directly and would not apply the filter.

  **Access.** The filters are part of the RWA classification add-on, enabled per organization. A request carrying either parameter from an organization without it is refused with `403`. Previously the parameters were unknown and silently ignored; no live client was sending them.

  **Affected endpoints:**

  * `GET /v1/fungibles/`
</Update>

<Update label="September 3, 2026" description="Failed transaction webhooks for smart-contract wallets" tags={["Change"]}>
  ## Failed-transaction webhooks for smart-contract wallets

  Webhooks are now delivered for failed transactions addressed to your smart-contract wallet. Available on EVM chains only.
</Update>

<Update label="September 2, 2026" description="Native asset implementation address documented" tags={["Docs"]}>
  ## Native assets have no implementation address

  The `address` field of a fungible implementation is now documented for the chain's native asset (ETH on Ethereum, HYPE on HyperEVM, SOL on Solana): `GET /v1/fungibles/` returns an empty string, while `fungible_info.implementations[]` on wallet endpoints returns `null`. Neither can be used with `filter[implementation_address]`. To fetch a native asset, use `GET /v1/fungibles/by-implementation?implementation=<chain_id>` or follow the `native_fungible` relationship on `GET /v1/chains/{chain_id}`. Documentation only, no response change.
</Update>

<Update label="August 28, 2026" description="asset_class on the positions endpoints" tags={["Feature"]}>
  ## `asset_class` is now returned on positions

  For organizations with the RWA add-on, `fungible_info` objects on `GET /v1/wallets/{address}/positions/` and `GET /v1/wallet-sets/{wallet_set_id}/positions/` now carry the `asset_class` attribute when the asset has a classification — same values as the fungibles endpoints; unclassified assets omit the field. A position's `receipt.fungible_info` carries it on the same terms. Responses for other organizations are unchanged.
</Update>

<Update label="August 25, 2026" description="asset_class in webhook payloads" tags={["Feature"]}>
  ## `asset_class` is now delivered via webhooks

  For organizations with the RWA add-on, `fungible_info` objects in webhook transaction payloads now carry the `asset_class` attribute when the asset has a classification — same values as the fungibles endpoints; unclassified assets omit the field. Payloads for other organizations are unchanged.
</Update>

<Update label="August 20, 2026" description="Filter charts by Uniswap V3/V4 LP NFTs" tags={["Feature"]}>
  ## Balance charts can be filtered by a Uniswap V3 or V4 LP NFT

  `filter[pool_addresses]` and `filter[exclude_pool_addresses]` on the balance-chart endpoints now accept an LP NFT written as `<position_manager_address>:<token_id>`, alongside the plain contract address they already took.

  This is what a Uniswap V4 position needs. A V4 pool has no contract address of its own — its pool id is a 32-byte hash — so before this change there was no value that selected one: the pool id was rejected with `400`, and the PositionManager address was accepted but matched nothing, returning `200` with an all-zero series. A V3 position can now be addressed either way, by its pool contract address or by its own LP NFT; both select the same position.

  ```
  filter[pool_addresses]=0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e:229217
  ```

  A raw V4 pool id is still rejected with `400`, and the error message now names the form that works. `token_id` must be the canonical decimal representation of an unsigned 256-bit integer: one or more decimal digits, no leading zeros, and a value from `0` through `2^256 - 1` (`115792089237316195423570985008687907853269984665640564039457584007913129639935`), inclusive. Invalid or out-of-range values return `400`. The maximum string length of each array item has increased from 44 to 121 characters, allowing a 42-character address, a colon, and up to 78 decimal digits. This limit controls string length, not numeric range. Regenerate your SDK if it validates request parameters client-side. Everything else is unchanged: the 25-item cap counts both forms together, the two parameters stay mutually exclusive, and `filter[positions]=only_simple` alongside either one still returns `400`.

  **Positions now expose the identifier.** Wallet and wallet-set position responses carry `receipt.nft_info` — `chain_id`, `contract_address` and `token_id` — on Uniswap V3 and V4 liquidity positions. Join the last two with a colon to get the value the chart filters accept. Positions backed by a fungible token, such as a Uniswap V2 LP token or an ERC-4626 vault share, continue to return `receipt.fungible_info` and are unaffected.

  **Clarifications** to behaviour that has not changed, previously undocumented:

  * Which value each protocol takes: the LP-token address for Uniswap V2, the pool contract address for Uniswap V3, the LP NFT for Uniswap V4, and the vault address for an ERC-4626 vault such as Morpho.
  * Addresses are case-insensitive, and one that is syntactically valid but matches none of the wallet's positions returns `200` with an all-zero series rather than an error.
  * Passing a pool filter without `filter[positions]` applies `no_filter`, not the usual `only_simple` default — otherwise the filter would select complex positions the default had already dropped.
  * The chart endpoints previously documented Uniswap V2 LP and Morpho vault positions as the only supported complex positions. Uniswap V3 and V4 have been charted in production for weeks; the descriptions now say so.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/charts/{chart_period}`
  * `GET /v1/wallet-sets/charts/{chart_period}`
  * `GET /v1/wallets/{address}/positions/`
  * `GET /v1/wallet-sets/positions/`
</Update>

<Update label="August 19, 2026" description="Field renamed" tags={["Change"]}>
  ## `rwa_class` is now `asset_class`

  The classification field on fungible attributes is renamed from `rwa_class` to `asset_class`. Values, availability (a paid add-on enabled per organization), and omission semantics are unchanged — only the field name.

  Why: `stablecoin` and `other_non_financial` are values of this field, so the old name implied every classified asset is an RWA. `asset_class` describes what the field actually carries.

  The old `rwa_class` name is not served alongside the new one. Organizations with the add-on enabled were notified directly with the cutover date.

  **Affected endpoints:**

  * `GET /v1/fungibles/`
  * `GET /v1/fungibles/{fungible_id}`
  * `GET /v1/fungibles/by-implementation?implementation={chain}:{address}`
</Update>

<Update label="August 14, 2026" description="Truthful PnL error responses" tags={["Fix"]}>
  ## PnL endpoints no longer ask you to retry requests that cannot succeed

  Requests that can never be served now return a status code that says so, instead of one that invites a pointless retry loop.

  * **Wallets with over 1 million actions** previously returned `503` with a `Retry-After` header, even though retrying could never succeed. They now return `422` with no `Retry-After` header.
  * **Addresses Zerion does not track** previously surfaced as a `500 Internal Server Error`. They now return `400` naming the address. This covers contract addresses that are not recognized smart-contract wallets, burn addresses, and high-volume addresses such as exchange hot wallets. Smart-contract wallets like Safe and ERC-4337 accounts are tracked as normal.

  Genuinely transient conditions are unchanged: a cold wallet still returns `503` with `Retry-After`, and retrying still works. If you already retry on `503`, that logic keeps working — but a `503` now means the retry will actually help.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/pnl`
  * `GET /v1/wallet-sets/pnl`
</Update>

<Update label="August 13, 2026" description="Documentation" tags={["Docs"]}>
  ## `rwa_class` documentation clarified

  Two wording changes to the `rwa_class` field, both documentation-only — its values and availability are unchanged.

  * The description previously said the field was returned "for callers with access to this field", which didn't say how that access is obtained. It now states that the field is a paid add-on enabled per organization.
  * The `unknown` value no longer carries a "safe to block by default" recommendation. Whether an unclassified-but-likely RWA should be blocked, flagged, or simply labelled depends on what you are building, so the documentation now describes what the value means and leaves the handling to you.

  **Affected endpoints:**

  * `GET /v1/fungibles/`
  * `GET /v1/fungibles/{fungible_id}`
  * `GET /v1/fungibles/by-implementation?implementation={chain}:{address}`
</Update>

<Update label="August 6, 2026" description="Documentation" tags={["Docs"]}>
  ## Wallet NFT endpoints now correctly document EVM-only addresses

  The wallet NFT endpoints previously documented the shared `address` parameter as accepting either an EVM or Solana address. Zerion's NFT data does not support Solana wallets, so these endpoints now document an EVM-only address parameter. This is a documentation-only clarification — the endpoints have always rejected Solana addresses with a `400`; the parameter description simply didn't reflect that.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/nft-positions/`
  * `GET /v1/wallets/{address}/nft-collections/`
  * `GET /v1/wallets/{address}/nft-portfolio`
</Update>

<Update label="August 3, 2026" description="Fungible real-world asset classification" tags={["Feature"]}>
  ## Real-world asset classification for fungibles

  API customers with the `rwa` role can receive an optional `rwa_class` in fungible attributes: `commodity`, `tokenized_stock`, `tokenized_treasury`, `stablecoin`, `other_financial`, `other_non_financial`, or `unknown`. These values distinguish tokenized commodities, equities and ETFs, treasury and government-debt products, fiat-pegged stablecoins, other classified financial instruments, non-financial real-world assets, and likely RWAs awaiting classification. The field is omitted when an asset is unclassified or its classification has been cleared.

  **Affected endpoints:**

  * `GET /v1/fungibles/`
  * `GET /v1/fungibles/{fungible_id}`
  * `GET /v1/fungibles/by-implementation?implementation={chain}:{address}`
</Update>

<Update label="July 17, 2026" description="Pool filtering for balance charts" tags={["Feature"]}>
  ## Filter wallet balance charts by liquidity-pool / vault position

  New `filter[pool_addresses]` and `filter[exclude_pool_addresses]` query parameters on the wallet and wallet-set balance chart endpoints scope the chart to specific liquidity-pool / vault positions by contract address — the Uniswap V2 LP-token or ERC-4626 vault (e.g. Morpho) address. Pass up to 25 addresses. `filter[pool_addresses]` charts only the matching protocol positions; `filter[exclude_pool_addresses]` removes them while keeping the rest of the portfolio. The two are mutually exclusive — combining them returns `400`. These filters select complex (protocol) positions, so combining either with `filter[positions]=only_simple` also returns `400`.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/charts/{chart_period}`
  * `GET /v1/wallet-sets/charts/{chart_period}`
</Update>

<Update label="July 17, 2026" description="DeFi position receipt tokens" tags={["Feature"]}>
  ## Receipt tokens for DeFi positions

  Wallet and wallet-set position responses now include an optional receipt for a token representing a DeFi position.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/positions/`
  * `GET /v1/wallet-sets/positions/`
</Update>

<Update label="June 8, 2026" description="Documentation" tags={["Docs"]}>
  ## Chart point granularity documented for balance & price charts

  Documented the sampling interval (spacing between `points`) for each `chart_period` on the chart endpoints. This is a documentation-only clarification — the cadence has always been emitted by these endpoints; it simply wasn't described in the reference.

  Each period samples its time window at a fixed interval: `hour` → 10s, `day` → 5m, `week` → 30m, `month` → 2h, `3months` → 6h, `6months` → 12h, `year` → 1d, `5years` → 4d. For `max`, the interval is derived from available history (so it varies by wallet or asset).

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/charts/{chart_period}`
  * `GET /v1/wallet-sets/charts/{chart_period}`
  * `GET /v1/fungibles/{fungible_id}/charts/{chart_period}`
  * `GET /v1/fungibles/by-implementation/charts/{chart_period}`
</Update>

<Update label="June 4, 2026" description="New feature" tags={["Feature"]}>
  ## Wallet balance charts — include DeFi protocol positions

  Added `filter[positions]` to the wallet and wallet-sets balance chart endpoints, letting you include complex DeFi protocol positions (liquidity pools, vaults) alongside plain token balances:

  * `only_simple` (default) — token and native-coin balances held directly in the wallet. Matches previous behavior, so existing integrations are unaffected.
  * `only_complex` — complex DeFi protocol positions only.
  * `no_filter` — both.

  **Uniswap V2 LP positions are supported today**, and support for more protocols is rolling out over time. Positions from protocols that aren't yet supported are omitted from the chart.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/charts/{chart_period}`
  * `GET /v1/wallet-sets/charts/{chart_period}`

  ```bash theme={null}
  curl -g -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8da6bf26964af9d7eed9e03e53415d37aa96045/charts/day?filter[positions]=no_filter"
  ```
</Update>

<Update label="June 1, 2026" description="Solana raw amounts" tags={["Feature", "Breaking"]}>
  ## Raw on-chain amounts for Token-2022 ScaledUiAmount assets

  For Token-2022 ScaledUiAmount (rebasing) assets such as SPYx, `quantity.int` is now the objective on-chain **raw** amount in base units. Use this value to build correct on-chain transactions, including max-balance (send-max) transfers, which fail on-chain when built from the scaled display amount.

  * `quantity.int` — objective on-chain raw amount in base units.
  * `quantity.float` / `quantity.numeric` — ready-to-display value = `int / 10^decimals`. For ScaledUiAmount assets, the display value is `int × multiplier / 10^decimals`.

  Non-ScaledUiAmount assets are unaffected: their `int` already equals the on-chain amount.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/positions/`
  * `GET /v1/wallet-sets/positions/`

  **Breaking change:** For ScaledUiAmount assets, `quantity.int` previously carried the scaled display amount and now carries the raw on-chain amount. Read the display value from `quantity.float` or `quantity.numeric`.
</Update>

<Update label="May 29, 2026" description="Limit increase" tags={["Improvement"]}>
  ## Wallet NFT positions — page size cap raised to 500

  `GET /v1/wallets/{address}/nft-positions/` now accepts `page[size]` values up to **500** (previously capped at 100). This lets you fetch large NFT wallets in significantly fewer requests. Existing requests are unaffected — this only raises the maximum; the default page size is **50**.

  **Affected endpoint:**

  * `GET /v1/wallets/{address}/nft-positions/`

  ```bash theme={null}
  curl -g -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0x.../nft-positions/?page[size]=500"
  ```

  **Migration:** No client changes required. To reduce round-trips on large wallets, raise `page[size]` up to 500 and keep following the `links.next` cursor to paginate.
</Update>

<Update label="May 19, 2026" description="Limit increase" tags={["Improvement"]}>
  ## Find wallets within subscription — page size cap raised to 2000

  `GET /v1/tx-subscriptions/{subscription_id}/wallets` now accepts `page[size]` values up to **2000** (previously capped at 100). The default page size remains 100, so existing clients are unaffected.

  **Affected endpoint:**

  * `GET /v1/tx-subscriptions/{subscription_id}/wallets`

  ```bash theme={null}
  curl -g -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/tx-subscriptions/77e77447-1586-40e8-a75b-467ef939a0b1/wallets?page[size]=2000"
  ```
</Update>

<Update label="May 13, 2026" description="New feature" tags={["Feature"]}>
  ## Wallet balance charts — exclude fungibles

  Added `filter[exclude_fungible_ids]` to the wallet and wallet-sets balance chart endpoints — drop a small set of tokens from the chart instead of enumerating everything you want to keep. Same shape as `filter[fungible_ids]`: comma-separated, capped at 25 ids. Combining it with `filter[fungible_ids]` returns `400` — pick one.

  **Affected endpoints:**

  * `GET /v1/wallets/{address}/charts/{chart_period}`
  * `GET /v1/wallet-sets/charts/{chart_period}`

  ```bash theme={null}
  curl -g -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8da6bf26964af9d7eed9e03e53415d37aa96045/charts/day?filter[exclude_fungible_ids]=eth,usd-coin"
  ```
</Update>

<Update label="May 13, 2026" description="Endpoint deprecation" tags={["Deprecation"]}>
  ## Swap Offers API — deprecated

  `GET /v1/swap/offers/` is now deprecated and has been hidden from the API reference. Use `GET /v1/swap/quotes/` instead, which covers the same use cases and adds native support for Solana and EVM ↔ Solana bridges.

  **Sunset date:** the endpoint will be permanently disabled on **July 1, 2026**. Requests after that date will fail.

  **Migration:**

  * Switch calls from `GET /v1/swap/offers/` to `GET /v1/swap/quotes/`.
  * The response body shape differs: transactions are wrapped in chain-agnostic `evm` / `solana` envelopes, and fees are split into separate `protocol_fee` / `bridge_fee` / `network_fee` blocks. See the Swap Quotes reference for the full schema.
  * Quotes are returned best-first (sorted by `output_amount_after_fees`), matching the ordering you already get from `/v1/swap/offers/`.
</Update>

<Update label="May 8, 2026" description="Documentation clarifications" tags={["Fix"]}>
  ## Reference docs — clarifications across PnL, swap, and wallet endpoints

  Refreshed several reference-doc descriptions to better match how the API actually behaves. **No behavior changes** — every update describes behavior that's already live in production.

  **Clarifications:**

  * **PnL `since` / `till` is a hard limit, not a guideline** (`GET /wallets/{address}/pnl`, `GET /wallet-sets/pnl`). PnL is pre-computed at standard marks (`now`, `1 day ago`, `1 week ago`, `1 month ago`, `1 year ago`, `beginning of the year`); other timestamps are accepted only when fewer than 3,000 transactions sit between your timestamp and the nearest mark, otherwise the request errors out.
  * **Swap endpoints rewritten** (`GET /v1/swap/offers/`, `GET /v1/swap/fungibles/`). `/v1/swap/offers/` returns ready-to-sign transaction data in a single call (0.8% Zerion fee included in the quoted amounts) — not a multi-step quote-then-execute flow as previously documented. `/v1/swap/fungibles/` is a token-picker helper for cross-chain swaps only.
  * **Swap section reordered** to `quotes` → `offers` → `fungibles`, surfacing `/v1/swap/quotes/` as the modern primary endpoint.
  * **Wallet address validation documented** (`WalletAddress` parameter, `GET /wallets/{address}/transactions/`). Addresses must be valid EVM or Solana; untracked addresses return `400` (API-1903).
  * **`filter[operation_types]` duplicated enum removed** (`GET /wallets/{address}/transactions/`, `GET /wallets/transactions/`, `GET /wallet-sets/transactions/`). The bulleted list was rendered twice and the inline copy was stale (missing `bid`); the schema `$ref` is now the single source of truth.
  * **`PATCH /v1/tx-subscriptions/{id}/wallets` 100-address batch cap documented**. The `add` and `remove` arrays accept at most 100 addresses per request; `maxItems: 100` is now in the schema.

  **Migration:** No client changes required. API responses and error behavior are unchanged — these updates only correct the reference documentation to match the limits the API has already been enforcing.
</Update>

<Update label="May 6, 2026" description="Documentation fix" tags={["Fix"]}>
  ## Webhooks — payload example fix

  Fixed two errors in the example payloads on the [Webhooks](/webhooks) page. **No breaking changes** — the production webhook payload format is unchanged; only the documentation examples were wrong.

  **Corrections:**

  * `data.type` is `"callback"` (the docs incorrectly showed `"transaction_notification"`).
  * The rollback indicator `deleted: true` is on the transaction resource at `included[0].attributes.deleted` (the docs incorrectly showed it on `data.attributes.deleted`).

  **Migration:** No client changes required. Verify your webhook handler reads the rollback flag from the transaction resource inside `included`, not from `data.attributes`.
</Update>

<Update label="May 5, 2026" description="New feature" tags={["Feature"]}>
  ## Swap Quotes API — new endpoint

  Added `GET /v1/swap/quotes/` — returns swap quotes from multiple liquidity sources for both same-chain swaps and cross-chain bridges. Supports EVM chains and Solana, including EVM ↔ Solana bridges.

  ```bash theme={null}
  curl -g -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/swap/quotes/?input[chain_id]=base&input[fungible_id]=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&input[amount]=0.001&output[fungible_id]=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&from=0xd8da6bf26964af9d7eed9e03e53415d37aa96045&to=0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
  ```

  **Differences from `/v1/swap/offers/`:**

  * Native support for Solana wallets and bridges between EVM and Solana chains.
  * The response body has been restructured: transactions are wrapped in chain-agnostic `evm`/`solana` envelopes, fees are split into separate `protocol_fee` / `bridge_fee` / `network_fee` blocks.

  The legacy `/v1/swap/offers/` endpoint remains for backward compatibility.
</Update>

<Update label="April 21, 2026" description="New feature" tags={["Feature"]}>
  ## Transactions API — fee acts

  Transactions and acts may now carry the type `fee`, and a new `fee_kind` field on `Act` classifies fee acts. **No breaking changes** — this is an additive change.

  **New `fee` type value:**
  Both the transaction-level `type` enum and the per-act `type` (`ActType`) enum now include `fee`. A `fee`-typed act represents a fee charge that appears alongside existing acts in the transaction's `acts` array; a transaction whose primary operation is a fee charge will surface `type: fee` at the top level.

  **New `fee_kind` field on `Act`:**
  Optional string that classifies a fee act. Only present on acts of type `fee`.

  * **`ui`** — fee charged by the UI / client application (e.g., a wallet or dApp frontend)
  * **`jito`** — Jito tip paid on Solana for priority inclusion

  **Affected endpoints:**

  * `GET /wallets/{address}/transactions/`
  * `GET /wallet-sets/transactions/`

  **Migration:** No client changes required. Clients that enumerate transaction or act types should be prepared to receive `fee` in addition to the previously documented values; unknown types should be handled gracefully. To surface fee acts to end users, render acts with `type: fee` and optionally distinguish them by `fee_kind`.
</Update>

<Update label="March 30, 2026" description="New feature" tags={["Feature"]}>
  ## Wallet Sets API — new endpoints

  Added five new endpoints for wallet sets — aggregated portfolio data across up to one EVM and one Solana address simultaneously.

  Pass one or two addresses via the `addresses` query parameter (at most one EVM and one Solana address):

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallet-sets/portfolio?addresses=0x42b9df65b219b3dd36ff330a4dd8f327a6ada990,8BH9pjtgyZDC4iAQH5ZiYDZ1MDWC98xki2V8NzqqKW3K"
  ```

  **New endpoints:**

  * `GET /wallet-sets/portfolio`
  * `GET /wallet-sets/positions/`
  * `GET /wallet-sets/transactions/`
  * `GET /wallet-sets/charts/{chart_period}`
  * `GET /wallet-sets/pnl`
</Update>

<Update label="March 20, 2026" description="New feature" tags={["Feature"]}>
  ## Fungibles API — sort by trading volume

  Added 24-hour trading volume as a new sort option for `GET /fungibles/`.

  * **`-market_data.trading_volumes.volume_1d`** — highest volume first
  * **`market_data.trading_volumes.volume_1d`** — lowest volume first

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/fungibles/?sort=-market_data.trading_volumes.volume_1d"
  ```
</Update>

<Update label="March 11, 2026" description="New feature" tags={["Feature"]}>
  ## Fungibles API — new fields

  Added trading volume and deployment date fields to fungible data. **No breaking changes.**

  **New fields in `FungibleAttributes.market_data`:**

  * `trading_volumes.volume_1d` — total 24-hour trading volume across all chains

  **New fields in `AttributesImplementation`** (new dedicated type for `implementations` array, backward compatible with all existing fields):

  * `market_data.trading_volumes.volume_1d` — 24-hour trading volume on this chain
  * `deployment_date` — ISO 8601 datetime when the token contract was deployed
</Update>

<Update label="February 9, 2026" description="Documentation fix" tags={["Fix"]}>
  ## Transactions API — OpenAPI documentation fix

  Fixed OpenAPI schema inconsistencies between documentation and implementation for the `/transactions` endpoints. **No breaking changes** — API responses remain unchanged, only the OpenAPI spec was corrected.

  **Nullable fields corrected:**

  * **Fee**: `fungible_info`, `price`, `value` marked as nullable
  * **Refund**: `fungible_info`, `price`, `value` marked as nullable
  * **Transfer**: `price`, `value` marked as nullable
  * **Fungible Info**: `icon` marked as nullable

  **Missing fields documented:**

  * Transaction attributes: `address`, `refund`, `delegations`
  * Fungible Info: `id`

  **Migration:** No client changes required. Clients using generated models should ensure they handle `null` values, as these were already nullable in practice.
</Update>

<Update label="February 4, 2026" description="New feature" tags={["Feature"]}>
  ## Chart periods — new time values

  Added two new time period values to the `chart_period` parameter:

  * **`6months`** — 6-month chart period
  * **`5years`** — 5-year chart period

  These complement the existing options: `hour`, `day`, `week`, `month`, `3months`, `year`, and `max`.

  **Affected endpoints:**

  * `GET /wallets/{address}/charts/{chart_period}`
  * `GET /fungibles/{fungible_id}/charts/{chart_period}`
  * `GET /fungibles/by-implementation/charts/{chart_period}`

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8dA.../charts/6months"
  ```
</Update>

<Update label="January 7, 2026" description="New feature" tags={["Feature"]}>
  ## Portfolio API — sync parameter

  Added new `sync` query parameter to the `/wallets/{address}/portfolio` endpoint.

  * **`true`**: Triggers a position sync and waits up to 30 seconds for fresh portfolio data before responding.
  * **`false`** (default): Returns immediately with cached data.

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8dA.../portfolio?sync=true"
  ```

  Clients should configure appropriate timeout settings when using `sync=true`.
</Update>

<Update label="November 19, 2025" description="New feature" tags={["Feature"]}>
  ## Positions API — sync parameter

  Added new `sync` query parameter to the `/wallets/{address}/positions` endpoint.

  * **`true`**: Waits up to 30 seconds for protocol positions to be updated and returns fresh data.
  * **`false`** (default): Returns immediately with available position data.

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8dA.../positions?sync=true"
  ```

  Clients should configure appropriate timeout settings when using `sync=true`.
</Update>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.