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

# Changelog

> Release notes for the Derive API.

Release notes for the Derive v3 API, newest first. Subscribe to the [RSS feed](https://docs.derive.xyz/changelog/rss.xml)
to be notified of new entries.

<Note>
  Migrating from v2? See [Migrating from V2](/migrating/v3-improvements).
</Note>

<Update label="October 9, 2026">
  ## Public subaccount lookup

  * **`public/get_subaccounts`** returns the subaccount IDs that a wallet owns. It takes the same `wallet`
    param and returns the same shape as `private/get_subaccounts`, but needs no authentication. A wallet with no
    account returns an empty list.

  All changes are additive.
</Update>

<Update label="October 7, 2026">
  ## Maker RFQ history

  * **`private/get_maker_rfq_history`** lists filled, cancelled and expired RFQs that you were eligible to quote
    as a maker, including RFQs you did not quote. It takes the same filters as `private/poll_rfqs`, but
    `from_timestamp` and `to_timestamp` filter on RFQ creation time. Without `from_timestamp`, it returns the
    30 days before `to_timestamp` (or before now). Results have the `private/poll_rfqs` RFQ shape, with
    `fill_rate` and `recent_fill_rate` set to `null`.
  * `private/poll_rfqs` returns only open RFQs, including partially filled ones. In v2 it also returned filled,
    cancelled and expired RFQs. Use `private/get_maker_rfq_history` for those.

  All changes are additive.
</Update>

<Update label="October 5, 2026">
  ## Forwarded withdrawals to home chains

  Withdrawals of bridged tokens can now go back to their home chain in one step. See
  [Forwarded withdrawals](/trading/transfers-withdrawals#forwarded-withdrawals).

  * **`private/register_withdraw_address`** returns a withdraw address for a `(recipient, chain_id)`.
    Withdraw to it with `private/withdraw`, and Derive bridges the payout to the recipient. Derive pays the
    bridge fee.
  * **`private/get_withdrawal_history`** entries to a withdraw address carry a new `forward` object with the
    forward's status, bridge message id and destination tx.
  * **`private/get_withdraw_addresses`** lists your withdraw addresses, where each forwards to, and whether
    it is on your whitelist.
  * New errors from `private/register_withdraw_address`: `withdraw_destination_unsupported` (11046) and
    `invalid_withdraw_recipient` (11047).

  All changes are additive.
</Update>

<Update label="October 2, 2026" tags={["Breaking"]}>
  ## `public/get_all_instruments` with `expired: true` lists only expired options

  For `instrument_type: "option"`, `expired: true` now returns **only expired options**.
  Previously it returned live and expired options together. `expired: false` is unchanged and
  returns live options.

  * **`risk_universe_id` now filters expired options.** It was ignored for them before.
  * `pagination.count` and `num_pages` count only expired options.
  * An empty listing returns `instrument_not_found` (12001), as every other empty listing does.
  * Perps and spot ignore `expired`, as before.

  An option enters the `expired: true` listing up to a minute before it expires, so it does not
  drop out of both listings at expiry. For a few minutes after settlement, its
  `option_details.settlement_price` in this listing can be `null`. `public/get_instrument` returns
  the settlement price at once.

  To list live and expired options in a way that works before and after this change, call
  `expired: false`, then `expired: true`. Merge the results by `instrument_name`,
  and treat `instrument_not_found` (12001) as an empty result.
</Update>

<Update label="September 25, 2026">
  ## History endpoints report `asset` as the currency name

  `private/get_deposit_history`, `private/get_withdrawal_history` and
  `private/get_erc20_transfer_history` now return `asset` as the currency name (e.g. `"USDC"`),
  matching v2 and the `asset_name` these operations are submitted with. Previously the field
  carried the protocol spot-asset contract address. `private/get_withdrawal_history` still reports
  the on-chain token under `erc20_address`.
</Update>

<Update label="September 17, 2026" tags={["Breaking"]}>
  ## `public/get_assets` is removed

  The route reported every asset of one `asset_type` for a currency, but only ever from the
  fallback risk universe, so its perp and lending figures did not describe any tradeable market.
  Nothing consumed it.

  Read assets from the endpoints that are keyed by risk universe instead:

  * `public/get_currency` and `public/get_all_currencies` — the option, perp and spot assets
    registered to a currency, with per-universe OI, discounts and lending.
  * `public/get_all_instruments` and `public/get_instrument` — tradeable instruments and their
    type-specific details.
</Update>

<Update label="September 17, 2026">
  ## Perp margin rates and max leverage are public again

  `srm_perp_margin_requirements` returns, carrying the v2 field set — `im_perp_req`, `mm_perp_req`
  and `max_leverage` — as decimal strings. `max_leverage` is `1 / im_perp_req` rounded to 2
  decimals.

  It is reported in two places, both keyed by risk universe:

  * `public/get_currency` and `public/get_all_currencies` — on each entry of `perp.universes[]`.
  * `public/get_instrument` and `public/get_all_instruments` — inside `perp_details`, for the
    instrument's own risk universe.

  The object is absent (or `null`) where no Standard Risk Manager in that universe prices the
  currency, and on option assets. A currency whose perp market has been scaled out reports
  `im_perp_req` of `"0"` and `max_leverage` of `"0"` — v2's behaviour, retained.

  The v2 path is not restored: the object no longer sits at the top level of the currency
  response. See [Migrating from V2](/migrating/breaking-changes).
</Update>

<Update label="September 16, 2026">
  ## Deposits that arrive over a bridge carry their origin

  `public/get_pending_deposits` and `private/get_deposit_history` now report where a deposit came
  from when it reached your escrow over a bridge. No method was added, and nothing about crediting
  is different: a bridge delivers an ordinary ERC-20 transfer into the escrow, which is swept and
  credited exactly as a transfer from your own wallet would be.

  * `public/get_pending_deposits` lists every bridge into your escrows in `pending_deposits[]`, one
    entry per deposit throughout. While the funds are in transit, before any L1 transaction exists,
    the entry has `status: "bridging"`; once the L1 deposit is recorded it is that deposit's entry,
    with its own `status`. Key a bridging entry on `bridge_to_l1.bridge_id`: it gains `tx_hash` and
    `log_index` when the deposit lands.
  * **Now optional** on `pending_deposits[]` entries, absent while `bridging`: `action_id`,
    `tx_hash`, `log_index` and `block_number`. `amount` is also absent until the bridge delivers,
    then what arrived. They remain present on every L1 entry.
  * Entries carry an optional **`bridge_to_l1`** object: `rail`, `bridge_id`, `source_chain_id`,
    `source_tx_hash`, `source_address` (your wallet on the source chain), `bridge_status`,
    `substatus`, `deposit_address`, `token`, `expected_amount` (source-chain units, an upper bound
    before fees), `receiving_tx_hash`, `receiving_token`, `receiving_amount`, `delivered_at_ms` and
    `expires_at_ms`. `bridge_status` moves `submitted` →
    `delivered` → `matched`, or ends `failed` (refunded on the source chain), `expired` (unresolved
    past `expires_at_ms`) or `unmatched` (delivered but not credited within 24 hours; contact
    support).
  * `private/get_deposit_history` entries gain an optional **`bridge_origin`** object with `rail`,
    `source_chain_id`, `source_tx_hash` and `source_address`, so provenance survives after the
    deposit is applied.
  * `private/get_deposit_history` entries also gain optional **`l1_tx_hash`** and **`l1_sender`**:
    the L1 transaction that moved the funds into your deposit address, and who sent it (your
    wallet, an exchange, or a bridge's relayer). `tx_hash` remains the settlement batch's commit,
    `null` until the batch settles. Both are absent when no tracked L1 transfer backs the deposit,
    or when one action credited several transfers at once.

  `rail` is `lifi` today; the field exists so a second bridge protocol can be added without a
  breaking change. A bridge sent outside Derive's own quotes is not tracked and appears as a plain
  deposit, exactly as before.

  See [Programmatic Onboarding](/getting-started/depositing).
</Update>

<Update label="September 15, 2026" tags={["Breaking"]}>
  ## Testnet settlement contracts redeployed

  The Derive v3 **testnet** (Ethereum Sepolia, chain ID `11155111`) settlement contracts were
  redeployed. The sequencer only watches the new deployment: a deposit sent to a previous
  `OnchainActionManager` is **not credited**, and earlier withdrawal outboxes receive no new payouts.

  | Contract | Address |
  | - | - |
  | `ACTION_MANAGER` | `0xd3625eCf97E5554C62A48Ac1c9284C9dCeFceB68` |
  | `VAPP` | `0x1573bde26338A9E6AA358638679A796c81E33246` |
  | `WITHDRAWAL_OUTBOX` | `0xFbB62CE2BbFdFdc8a60DDC22115aC29cf91B4566` |
  | `SPOT_VAULT` | `0x3FB79aafCD401CDD19e3d729241545955DDE0D48` |

  The mock ERC-20 tokens are unchanged, but the **protocol spot-asset addresses** (the `asset`
  argument to `deposit` and `depositToNewSubaccount`) are new. Read them from
  `public/get_risk_universes` or `public/get_all_currencies` rather than hardcoding them.

  If you hardcoded a testnet `ACTION_MANAGER`, update it — see [Contracts](/getting-started/contracts)
  and [Programmatic Onboarding](/getting-started/depositing). Signing constants (module addresses,
  `ACTION_TYPEHASH`, the EIP-712 domain separator) are unaffected.
</Update>

<Update label="September 11, 2026" tags={["Breaking"]}>
  ## Proven operations share one per-wallet rate-limit budget

  Every method that submits a proven operation outside order matching now carries the `proven`
  rate-limit class and decrements a single per-wallet budget of **1 TPS** by default (5 points per
  5s window on mainnet). Previously most of these methods drew from the far larger `non_matching`
  budget, and a few had their own per-method budget.

  Affected methods: `private/transfer_spot`, `private/transfer_spot_external`,
  `private/transfer_positions`, `private/withdraw`, `private/liquidate`,
  `private/set_session_key`, `private/delete_subaccount`, `private/update_whitelisted_recipients`,
  `private/create_vault`, `private/mint_vault_shares`, `private/burn_vault_shares`,
  `private/request_vault_deposit`, `private/request_vault_withdraw`,
  `private/cancel_all_vault_requests`, `private/force_burn`.

  * `public/getRateLimits` reports the budget under `remaining_per_endpoint.proven`.
  * Rejections use the usual `-32000` code with message `Rate limit exceeded: {wallet}-proven`.
  * Order, quote, and RFQ execution methods are unaffected.

  See [Rate Limits](/rate-limits).
</Update>

<Update label="July 31, 2026" tags={["Breaking"]}>
  ## `private/create_session_key` renamed to `private/set_session_key`

  The route now matches what the action does (register, refresh, **or** retire a key by writing a
  nearer expiry) and its L1 counterpart, the `SetSessionKey` onchain action. Everything about the
  rename is mechanical:

  * Route: `private/create_session_key` → **`private/set_session_key`** (and the debug variant
    `private/create_session_key_debug` → `private/set_session_key_debug`). The old route names
    are gone.
  * Protocol scope: `create_session_key` → **`set_session_key`** in `protocol_scopes` on
    registration requests and in `private/session_keys` responses.
  * TypeScript SDK: `client.sessionKeys.create(...)` → **`client.sessionKeys.set(...)`**;
    `ProtocolScopeCode.CreateSessionKey` → `ProtocolScopeCode.SetSessionKey`.

  ## Signed action payloads now use canonical Solidity ABI encoding

  Every signed action's `data` bytes are now exactly what Solidity `abi.encode` produces — if you
  sign with a standard ABI coder (ethers `AbiCoder`, viem `encodeAbiParameters`, `abi.encode` in a
  contract), nothing changes for you. Hand-rolled encoders must drop the previous non-standard
  layouts, which are **no longer accepted**:

  **`private/set_session_key` and the L1 `SetSessionKey` action (type 51)**

  The payload is canonical `abi.encode(address sessionKey, uint256 expirySec, uint256[] scopes,
    uint256[] subaccountIds)` — dynamic arrays sit behind standard offset words, each prefixed by its
  length word. The old hand-packed layout (`[key][expiry][scopeCount][subaccountCount][scopes…] [subaccounts…]`, no offsets) is rejected. In Solidity, build the L1 payload with a plain
  `abi.encode` call instead of packing words manually.

  **`private/update_whitelisted_recipients`**

  The payload is canonical `abi.encode(address[] add, address[] remove)`. The old hand-packed
  layout (`[addCount][removeCount][adds…][removes…]`, no offsets) is rejected.

  **Orders (`private/order`) and liquidations (`private/liquidate`)**

  Negative `int256` values (`limit_price`, `amount`, `price_limit`) are now full 32-byte
  two's-complement words, sign-extended through the high 16 bytes — standard ABI coder output.
  Previously the server produced and expected a non-standard form with the value packed into the
  low 16 bytes only, which broke standard-signing clients on negative liquidation price limits.
  Non-negative values encode identically, so most existing signatures are unaffected.

  Decoding is also strict across these payloads: offset words must point at their canonical
  positions, lengths must match the byte count, and value words must fit their field's range —
  dirty high bytes are rejected instead of silently truncated, matching Solidity `abi.decode`.

  See [Action signing](/authentication/action-signing) for the per-module payload layouts.
</Update>

<Update label="July 22, 2026" tags={["Breaking"]}>
  ## Settlement status unified under `batch_status`

  The `tx_status` field and the `TxStatus` type are removed. Every route and channel that reported
  settlement status now uses **`batch_status`**, typed as the shared `BatchStatus` enum — `Batching`,
  `Executing`, `Proving`, `Settling`, `Settled` and their `…Error` counterparts — and `null` until
  the operation is picked up into a batch.

  This replaces the old granular transaction states (`applied`, `in_batch`, `proving`, `submitted`)
  **and** the lowercase matching-engine values (`requested`, `pending`, `settled`, `reverted`,
  `ignored`, `timed_out`), which are all **gone** across the entire API. There is now one status
  field, one set of values.

  **REST methods**

  * `public/get_trade_history` — optional `batch_status` request filter (unset returns trades in every
    batch state) and on each trade
  * `private/get_trade_history` — `batch_status` on each trade
  * `private/order`, `private/replace` — `batch_status` on each `trades[]` entry (always `null` at placement)
  * `private/send_quote`, `private/cancel_quote`, `private/replace_quote`, `private/get_quotes`,
    `private/transfer_positions` — `batch_status` on each quote (present only for executed quotes)
  * `private/get_deposit_history`, `private/get_withdrawal_history`,
    `private/get_erc20_transfer_history`, `private/get_funding_history` — `batch_status` on each row
  * `public/get_transaction` — `status` uses the same `BatchStatus` values

  **WebSocket channels**

  * `trades.{instrument_type}.{currency}.{tx_status}` and `{subaccount_id}.trades.{tx_status}` — removed;
    settlement is no longer streamed. Poll `public/get_trade_history` for `batch_status` / `tx_hash` instead
  * `trades.{instrument_name}`, `trades.{instrument_type}.{currency}` — each event now carries the full
    trade detail (`wallet`, `subaccount_id`, `liquidity_role`, fees, realized PnL)
  * `{subaccount_id}.trades`, `{subaccount_id}.quotes` — `batch_status` on each payload item

  ## `instrument_type` is now a typed enum

  On the trade-history schemas, `instrument_type` is typed as the `AssetType` enum
  (`erc20` / `option` / `perp`) instead of a free-form string.

  See [Breaking changes → Settlement status](/migrating/breaking-changes) for the full route table
  and value reference.
</Update>


## Related topics

- [Programmatic Onboarding](/getting-started/depositing.md)


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