Skip to main content
Track what’s new and what’s changed in our API. We publish an entry for every user-facing change, and we’re explicit about whether a change is backwards compatible or requires a new API version. Subscribe to updates via the RSS feed at /changelog/rss.xml.
2026-10-29

Cumulative and annualised returns side by side

New API version 2026-10-29. See Versioning to migrate.
Returns no longer give you one rate per methodology whose meaning depends on the period length. mwrr and twrr are now objects that carry both figures, so you can show the return over the period and the annual rate without checking a flag. Requests pinned to 2026-10-01 or earlier keep the flat shape.Breaking
  • Account returns and position returns return mwrr and twrr as objects with two fields:
    • cumulative: the return over the period as a decimal, never annualised.
    • annualised: the annual rate as a decimal, set only for periods of a year or longer. It’s null for shorter periods.
  • The top-level annualised boolean is removed. To migrate, read mwrr.cumulative / twrr.cumulative where you showed the rate for periods under a year, and mwrr.annualised / twrr.annualised where you showed it for a year or longer.
Added
  • On 2026-10-01 and earlier, account and position returns also carry mwrr_period and twrr_period (cumulative over the period) and mwrr_annualised and twrr_annualised (annual rate, null for periods under a year), next to the existing mwrr, twrr, and annualised fields.
additions

Performance and return metrics enhancements

We’ve expanded earnings and returns endpoints with new fields for simpler return calculations and clearer annualization behavior.Added
  • money_in on account earnings and position earnings: the total amount deposited into the account or position over the period, each deposit converted at the exchange rate of its own day. Over the account’s whole life, this is the total deposited.
  • simple_return and simple_return_annualised on account and position earnings: simple_return is net divided by money_in, and simple_return_annualised applies annual compounding. Both are null when nothing was put in.
  • annualised on account returns and position returns: a boolean indicating whether the return rates are annualized (true for periods of a year or longer) or cumulative over the period.
  • rate_limited error code, returned when too many requests are made in a short period.
Changed
  • Descriptions for mwrr and twrr on account returns and position returns now clarify that they’re annualized for periods of a year or longer and cumulative over the period otherwise (see annualised).
2026-10-01

Trading configuration and consistent order validation

New API version 2026-10-01. See Versioning to migrate.
Instruments now describe their order rules in a single trading_configuration object, split into buy and sell. Quotes run the same checks as placement, so a quote fails exactly where the order it previews would. When a quoted order breaks a sizing rule, you get the quote back with the rule it breaks, so you can show your users what to change before they place it. Requests pinned to 2026-09-28 or earlier keep the legacy instrument fields and the previous error responses.Breaking
  • Instruments, wherever we return them (on their own or embedded in positions, orders, quotes, transactions, and valuations), no longer carry minimum_trading_quantity, minimum_initial_cash_investment, required_cash_increment, or enforce_trading_rules. Read the rules from trading_configuration instead:
    • minimum_initial_cash_investment is trading_configuration.buy.min_initial_cash_amount.
    • minimum_trading_quantity is trading_configuration.buy.min_cash_amount.
    • required_cash_increment and enforce_trading_rules have no replacement. We use null in the trading configuration when no rule applies.
  • Get an order quote returns 200 instead of 400 for an order that breaks a sizing rule: a quantity off the trading increment, a cash amount that buys less than one trading increment, or a minimum in trading_configuration. The quote carries its estimate as usual, with is_placeable: false and the rule in blockers. Placing the order as quoted still fails with the same error.
  • Get an order quote and Place an order return trading_rule_violated instead of invalid_request when an order breaks a rule in trading_configuration. context.rule names the rule (for example buy.min_initial_cash_amount), with context.required and context.actual. params still points at the field the order was sized by.
Added
  • trading_configuration on instruments, on every API version. buy carries modes, min_cash_amount, min_initial_cash_amount, min_quantity, and min_initial_quantity; sell carries modes, min_cash_amount, and min_quantity. A null minimum isn’t applied, and a sell minimum never blocks selling a whole position. Cash amounts are in the instrument’s trading currency.
  • is_placeable and blockers on every order quote. Each blocker carries the code and detail placement would return, and a context with rule, required, actual, and required_cash_amount: on a cash buy, the smallest cash_amount (fees included) that meets every buy rule.
  • trading_rule_violated error code.
  • insufficient_funds and insufficient_units blocker codes on order quotes. When a quote returns these blockers, the context tells you the balance check that failed: available and requested amounts, and the account currency (for funds) or the position’s available units (for units). You can use this to prompt users to add funds or adjust their position size before placing the order.
ChangedThese apply on every API version.
  • Get an order quote runs the same instrument and account checks as placement, so it can now return instrument_not_trading, instrument_buy_only, instrument_sell_only, instrument_too_close_to_maturity, currency_not_supported, insufficient_units, buy_order_forbidden, sell_order_forbidden, and professional_trader_required.
  • A quantity must be a multiple of the instrument’s trading_increment, on quotes and orders. We reject a quantity off the increment rather than trimming it.
  • Cash buys are sized by rounding the quantity down to the instrument’s trading_increment instead of to whole units. The quote’s estimate.quantity now matches the quantity the order executes, including the price buffer we apply.
  • Buy minimums apply to the cash the buy invests, net of fees. Quotes for limit cash buys now check them too. Rollover orders are exempt.
  • We no longer enforce a cash increment on buys. On 2026-09-28 and earlier, required_cash_increment is always 0 and enforce_trading_rules is always false.
  • An order that sends both cash_amount and quantity is rejected with invalid_param on quantity. Previously, quantity silently took precedence.
  • Selling an instrument the account holds no position in returns insufficient_units with context.available of "0".
  • trading_increment on instruments is returned at full precision (for example "0.00010000") instead of rounded to two decimal places.
additions

Order validation error codes

We’ve added new error codes to provide clearer feedback when orders conflict with instrument trading restrictions.Added
  • instrument_buy_only error code when you attempt to sell an instrument that only accepts buy orders.
  • instrument_sell_only error code when you attempt to buy an instrument that only accepts sell orders.
Changed
  • insufficient_units errors report context.available as an exact decimal string (for example "0.5") instead of a number rounded down to whole units.
  • Get an order quote errors for a cash buy that misses the instrument’s minimum initial investment or cash increment now point at body.cash_amount instead of body.quantity.
2026-09-28

Redesigned earnings responses

New API version 2026-09-28. See Versioning to migrate.
We’ve reshaped earnings (P&L) responses to provide a clearer picture of how earnings are distributed between market gains and FX currency movements, for accounts that hold investments or cash in currencies other than the account’s base currency. Requests pinned to 2026-09-02 or earlier keep the previous flat field layout, without this breakdown.Breaking
  • Retrieve account earnings (P&L) returns gross, fees, and net at the top level, plus a positions block and a cash block. The flat gross_*, net_*, realized_*, and unrealized_* fields are gone. net is gross minus fees. gross is positions.gross plus cash.gross.
  • The realized/unrealized and capital/income split moved under positions.attribution, which separates an investment effect (price changes and income, with exchange-rate movements stripped out) from a currency effect (exchange-rate movements on the money invested in positions). Each effect carries total, realized.capital, realized.income, unrealized.capital, and unrealized.income, all in the account’s currency. The currency effect is zero when everything is in the account’s currency.
  • position_earnings is no longer included in the account response by default. Pass include_positions to get each position’s earnings inline, as Retrieve position earnings (P&L) returns them.
  • The position response returns two views instead of one flat grid: trading, in the instrument’s own currency, and reporting, in the account’s base currency. currency, cost_basis, and gross now live inside each view rather than at the top level, and gross_unrealized_percentage is now trading.unrealized_percentage.
  • trading.attribution holds only an investment effect, since exchange rates play no part in the instrument’s own currency. reporting.attribution holds both investment and currency effects, with each leg converted at the exchange rate of the day it happened rather than a single period-end rate. Summed over all positions, the reporting figures give the account’s positions figures.
To migrate a position response, map the old flat fields onto the trading view:The account response follows the same pattern, with gross_total becoming gross, net_total becoming net, and the four buckets living under positions.attribution.investment and positions.attribution.currency.Added
  • account on position earnings responses (from 2026-09-28), the ID of the account holding the position.
  • cash on account earnings responses (from 2026-09-28): what uninvested foreign-currency cash gained or lost from exchange-rate movements, as cash.gross and cash.attribution.currency.total. It isn’t split into realized and unrealized.
Changed
  • Account earnings totals now include exchange-rate gains and losses on uninvested foreign-currency cash, on every API version. On 2026-09-02 and earlier this means gross_total and net_total can differ from gross_realized plus gross_unrealized by that cash currency effect.
additions

Instrument client categories and deposit status tracking

We now return client category information on instruments to support MiFID II compliance, and provide expanded deposit statuses for better visibility into their lifecycle.Added
  • target_client_categories on instrument responses, returning an array of client categories (retail, professional per se, professional on request) the instrument is intended for.
  • New deposit statuses: held, returning, returned, and cancelled, providing better tracking of the deposit lifecycle.
  • restricted as a new instrument rollout stage.
Changed
  • Fee charge amount field description now clarifies it reflects the notional the fee was priced on; it’s null when the amount doesn’t depend on a notional (as with flat fees).
additions

Instrument asset class allocation

We now return asset class allocation data for all instruments, showing how they split across equity, fixed income, cash, alternatives, or uninvested categories.Added
  • asset_class on instrument responses, showing how the instrument splits across asset classes (equity, fixed income, cash, alternatives, uninvested) with the weight in each class.
2026-09-02

Redesigned order quote responses

New API version 2026-09-02. See Versioning to migrate.
We’ve reshaped the Get an order quote response. Instead of one generic object for every quote, you now get a variant specific to the instrument and order mode you asked about, carrying only the economics that apply to that combination.Breaking
  • POST /accounts/{account_id}/order-quotes no longer returns a single generic OrderQuote object. It returns a union discriminated on quote_type, with one variant per instrument and order mode: amc_market_cash, bill_market_cash, bond_fixed_coupon_market_cash, bond_zero_coupon_market_cash, etf_market_cash, etf_limit_cash, etf_market_quantity, etf_limit_quantity, mmf_market_cash, or sell. Switch on quote_type before reading a quote.
  • The flat economics fields moved under an estimate object and dropped the estimated_ prefix: estimated_price, estimated_quantity, and estimated_cash are now estimate.price, estimate.quantity, and estimate.cash. fees, net_cash_amount, max_cost, and min_proceeds moved under estimate too. Each variant only carries the fields that apply to it.
  • instrument is now the full instrument object instead of an ID string.
Added
  • order_type on every variant, indicating whether the quote is for a market or limit order.
  • currency on every variant.
  • Instrument-specific economics in estimate: yield, annual_income, and accrued_interest for fixed income, plus notional, cost, price_buffer_percentage, and asof where they apply.
  • reservation object on every variant with what a placement would set aside: a cash amount vs a unit quantity (amount, denomination).
  • created_at on every variant.
  • fee_breakdown on every estimate, providing an itemized list of fees. Each line includes a label (the fee category), display_name (a human-readable name), and amount (the fee value in the quote’s currency). The line amounts sum to the total fees exactly.
additions

Enhanced idempotency key error handling

We now return more specific error codes when idempotency keys have conflicts or have expired, giving you better visibility into retry scenarios.Added
  • idempotency_key_conflict error code when the Idempotency-Key was already used for a resource outside the scope of this request.
  • idempotency_key_expired error code when the Idempotency-Key was already used, and the resource it created is older than the replay window.
additions

Fee charge collection tracking and earnings breakdowns

Fee charges now track how much has been collected and what’s outstanding, and earnings responses include gross capital and income fields for finer-grained reporting.Added
  • collected_amount on Retrieve a fee charge for the cash collected so far.
  • outstanding_amount on Retrieve a fee charge for what’s still owed on the charge.
  • collections array on Retrieve a fee charge with a history of collection events per fee charge.
  • gross_capital on earnings responses for capital gains before fees and taxes.
  • gross_income on earnings responses for income earnings before fees and taxes.
additions

Document references and confirmation type

Account documents can now point at the related order or object, and confirmation documents include an order_confirmation type.Added
  • reference on List account documents responses for the order or object the document evidences (order ID for confirmations, null for period documents).
  • order_confirmation on DocumentType for account document requests and responses.
  • position_not_open error code when you try to update a closed or closing position.
additions

Fixed-income instrument schema updates

We cleaned up the Bill instrument schema by removing the par_value field from responses. The field remains available on Bond instruments.Changed
  • Removed par_value from Bill responses. par_value is still present on Bond instruments.
additions

Enhanced fund details and fee variant support

We expanded ETF attributes to surface fund display metadata and currency details, and added a new endpoint to retrieve fees with their scoped variants.Added
  • New fields on ETF instrument responses: display_name, headline, currency_sentence, rhp_years, and fund_base_currency.
  • Retrieve a fee endpoint to look up a specific fee by ID, including its variants.
  • variants array on Fee objects containing scoped fee variants per instrument, instrument type, portfolio type, or transaction type.
additions

OAuth token endpoint RFC 6749 compliance

The POST /auth/token endpoint now returns RFC 6749-compliant error responses so you can distinguish between bad requests and authentication failures.Added
  • 401 Unauthorized response for client authentication failures on Issue an OAuth token, with an OAuthErrorBody payload following RFC 6749 §5.2.
Changed (backwards compatible)
  • 400 Bad Request response on POST /auth/token now uses OAuthErrorBody schema with error and error_description fields (RFC 6749 §5.2) instead of the standard error envelope.
additions

Permissions and reference expansion

You can now query your effective permissions in the current realm, and we support portfolio_transfer as a reference type for activity tracking.Added
  • List permissions to retrieve effective permissions for the authenticated actor, including scope and conditional details.
  • portfolio_transfer enum value on reference types for tracking portfolio transfers.
additions

Identify the end person on each request

When a call concerns an end person, send Person-Id so we can attribute the action for compliance. Client-User-Id is optional and helps with debugging.Added
  • Person-Id request header for our person ID (per_…) you’re acting on behalf of. Send this whenever the request concerns an end person. See Attribution.
  • Optional Client-User-Id request header for your own identifier of the same end user, for log correlation and support.
  • Error codes person_id_too_long and client_user_id_too_long when either header exceeds 255 characters.
additions

Fixed person reads

Fixed
  • Retrieve a person no longer returns 500 when optional person columns are null in storage.
additions

More reliable valuation

Instrument responses carry more ETF detail, and account valuation reads are more consistent across price providers.Added
  • trading_increment on instrument responses.
Changed (backwards compatible)
  • GET /accounts/{account_id}/valuation uses the latest price per timestamp across providers.
Fixed
  • Unrealized earnings percentage on GET /accounts/{account_id}/earnings no longer errors on zero cost basis.
additions

On-the-run bills and fixed-income pricing detail

You can look up the current on-the-run treasury bill per maturity period, and price responses now include accrued interest for bonds and bills.Added
  • GET /bills/otr to retrieve the on-the-run bill matrix for an issuer country. Periods with no matching bill are omitted.
  • ETF as an instrument type on List instruments and Retrieve an instrument.
  • accrued_interest on GET /prices responses.
  • next_coupon_date on fixed income instruments.
additions

Person creation and claim history

You can create persons directly and see the full claim audit trail by default when listing claims.AddedChanged (backwards compatible)
  • List claims for a person now defaults to include_history=true (full audit trail, newest first). Pass ?include_history=false to collapse to the current pending and verified row per claim type. See Claims.
additions
We added event polling, versioned legal document reads, and a broader set of webhook event types so you can react to orders, trades, positions, and accounts without polling.Added
  • GET /legal-documents and related version and file download endpoints.
  • Retrieve a person claim.
  • Webhook event types delivered to your registered endpoints: order.placed, order.pending, order.executing, order.filled, order.settled, order.cancelled, trade.executed, trade.settled, position.opened, position.closing, position.closed, account.opened, account.suspended, account.activated, account.closing, account.closed, and customer.closed. See Webhooks.
Changed (backwards compatible)
  • POST /auth/token accepts only the client_credentials grant.
  • purpose is required on POST /signed-uploads.
additions

Event reads and webhook delivery

You can list events from the API, and we started delivering webhook payloads automatically with retries.Added
  • List events for tenant-scoped event reads.
  • Automatic webhook delivery with retries for subscribed event types. See Deliveries.
2026-01-01

Initial API release

New API version 2026-01-01. See Versioning.
We shipped the first public version of our API. This is the baseline for date-based versioning; every future breaking change will ship as a new dated version, and everything below is available on 2026-01-01.Added
  • Authentication with bearer tokens. See Authentication.
  • Onboarding for persons, claims, and applications. See Onboarding.
  • Trading, holdings, valuation, and payments endpoints across accounts.
  • Webhooks with at-least-once delivery, signature verification, and automatic retries. See Webhooks.
  • Idempotency support for write requests. See Idempotency.