Skip to main content
Testnet runs testnet-v1.10.9. This page tracks OpenAPI and AsyncAPI spec changes as they land on testnet, anchored to the testnet release that first shipped each one — a change appears here before it reaches production, which currently carries these entries through testnet-v1.8.9. Building against production? See the mainnet changelog.
testnet-v1.10.9

testnet-v1.10.9

Ticker-based favorite markets and named subaccounts. /v1/api-meta/userPreferences gains three preference keys. favoritePerpMarkets stores favorites as an array of BASE-QUOTE perp tickers (e.g. ["BTC-USD"]) and favoriteSpotMarkets as an array of bare spot base symbols (e.g. ["BTC", "ETH", "NVDA"]), alongside the existing favoritedMarkets, which stays an array of numeric market IDs. subaccountPreferences stores a per-subaccount display name — a SubaccountPreferences object keyed by subaccount number, each entry { "name": "…" } (name max 64 chars, at most 256 entries), and the first UserPreferenceValue allowed to be an object rather than a scalar or array. The key set stays closed: PATCHing a key outside the enum returns 400.Breaking: affiliate rollingVolume renamed to volume30d. On GET /v1/affiliate/info, the affiliate’s own trailing-30-day notional fill volume field rollingVolume is renamed volume30d — otherwise unchanged (quote quantums, null/0 while the rollup is briefly unavailable). Update any client reading the old name. The separate rollingVolume on the /v1/accountStats reads is a different field and is not affected.
testnet-v1.10.7

testnet-v1.10.7

Look up a single trader on the leaderboard. GET /v1/leaderboard now accepts an address to return just that trader’s row — its volume, fees, and realized PnL over the window, plus its rank on the sortBy column wherever it sits on the board (not only within the top-N). Every leaderboard row also carries that rank field, computed on the active sortBy column in the same query so a row’s columns stay mutually consistent. When address is set, limit is ignored and an address that did not trade in the window returns an empty entries list.

testnet-v1.10.6

Spot fills — REST and WebSocket. GET /v1/spotFills returns an account’s spot fill history, newest-first — the seizure and loan-settle executions of the lending system (spot has no order book, so there is no maker/taker role or fee). Optional from/to (epoch microseconds) bound the window and optional accountIndex selects a subaccount. The new spotFills WebSocket channel streams the same executions live, with a snapshot of recent spot fills on subscribe (skip it with snapshot: false). No authentication required for the REST read.

testnet-v1.10.5

Dedicated spotPositions WebSocket channel. spotPositions streams a single account’s spot collateral holdings on its own channel, so clients can follow collateral without subscribing to the full perp positions stream. The snapshot carries the open holdings keyed by spot asset id; each update carries one changed holding with its post-event size, event valuation price, and a reason (DEPOSIT, WITHDRAWAL, SEIZURE, RELEASE, TRANSFER, UNKNOWN). With this move the positions channel is now perp-only — spot collateral no longer rides in a discriminated section of positions.Breaking: spot position qty renamed to size. On the REST spot-position surfaces — GET /v1/spotPositions rows and the spot positions on GET /v1/account — the holding-amount field qty is renamed size, matching the perp position surfaces. Update any client reading the old field name.

testnet-v1.10.4

Affiliates: all-time referred volume. GET /v1/affiliate/info adds totalReferredVolumeAllTime — the combined lifetime notional fill volume of all of the affiliate’s current direct (T1) referees, in quote quantums (1e9 = $1). Same definition as totalReferredVolume30d but with no time window. Reads 0 if the underlying rollup is momentarily unavailable.

testnet-v1.10.3

Borrow-interest settlement history. GET /v1/interest returns an account’s borrow-interest settlements, newest-first — the lending analog of GET /v1/funding: where funding charges an open perpetual, interest charges an open loan. Optional from/to (epoch microseconds) bound the window; when omitted, to defaults to now and from to 30 days before to. No authentication required.
testnet-v1.10.2

testnet-v1.10.2

Get a fill by trade id. GET /v1/fill/{tradeId} returns the single fill your account owns for a given tradeId (pass ?address=, optional accountIndex) — the point-lookup companion to GET /v1/fills. No authentication required.

testnet-v1.10.1

closedPnl now nets the fill fee. Across GET /v1/fills and the fills/account WebSocket rows, closedPnl is redefined as the cost-basis release (old borrowedCapital − new borrowedCapital − Δsize × price) minus the fill’s fee. Opening and same-direction add legs now report −fee (previously "0").
testnet-v1.9.13

New features

Spot collateral positions. GET /v1/spotPositions returns your open spot collateral positions, keyed by spot asset id — each row carrying the asset’s balance and its live oraclePrice (the USD price of the position’s price-source market, "0" while a market is briefly unpriced). The same oraclePrice field is added to the spot position rows on GET /v1/account. Two new error reasons, GetSpotPositionsFailed and SpotPositionsHandlerUnavailable, cover a failed read.

Breaking changes

Spot collateral fields renamed to spotAssetId / spotAssetDisplayName. The spot-asset identifier is unified across REST and WebSocket onto one name. Anywhere a spot-collateral row or transfer previously carried assetId / asset (and, on spot position rows, spotMarketId / spotMarketDisplayName; on the withdraw response, assetDisplayName), it now carries spotAssetId and spotAssetDisplayName. This touches POST /v1/withdraw (request, response, and the SpotAssetWithdraw EIP-712 payload — the signed field is now spotAssetId), GET /v1/account (netDepositsByAsset and spot position rows), and account transfer updates over both REST and the accounts / accountTransferUpdates WebSocket channels. Update any client reading or signing the old field names.
testnet-v1.9.11

New features

price_move price-alert notifications. GET /v1/api-meta/notifications adds a new price_move notification type, fired when a market’s mark price moves 5% or 10% off its most recent 24-hour low (an up alert) or high (a down alert). It reaches every subscriber who favorites the market or holds a position in it; opt out by adding price_move to the disabledAlerts user preference. The new NotificationPriceMovePayload reports the move in display decimals — direction, thresholdBps (500 or 1000), changePct, the anchor extreme (fromPrice/fromTs) and fire-time price (toPrice/toTs), elapsedSecs, and positionSide when the recipient holds a position in the market.
testnet-v1.9.1

New features

Multi-asset spot collateral. GET /v1/spotAssets returns the assets accepted as multi-asset collateral for lending — not tradable order books — for example SPY-USD-SPOT, each with its LTV, liquidation factor, price-source market, and supply caps. Spot-asset deposits and withdrawals flow through POST /v1/withdraw with a new assetId selecting the spot asset and a dedicated SpotAssetWithdraw EIP-712 payload; they can be rejected with the new statuses REJECTED_INVALID_MARKET, REJECTED_INSUFFICIENT_SPOT_BALANCE, and REJECTED_SPOT_POSITION_CAPACITY. GET /v1/account gains netDepositsByAsset, and account transfers add the types LENDING_DRAW, INTEREST_SETTLEMENT, SEIZURE_PAYMENT, and CLAIM_REPAYMENT.Lending rates WebSocket channel. The global lendingRates channel streams the exchange-wide borrow rate and cumulative borrow index — the lending analog of oraclePrices — emitting one frame per SOFR-driven rate segment with the annual borrow rate the segment opens at (ratePpm) and the global borrowIndex after the close.
testnet-v1.8.12

Updates

New rejection reason MISSING_MARK_PRICE. The market has no live mark price — a transient oracle gap — so the mark-based solvency gate cannot be evaluated. The move is not applied; retry once pricing resumes.
testnet-v1.8.9

New features

Invite codes are switched on (testnet only). GET /v1/affiliate/inviteCodes and POST /v1/affiliate/redeemInvite — long present in the spec but answering 503 — now answer on testnet; mainnet still returns 503 {"error":"Invite codes not available yet"} and the mainnet changelog will announce that rollout. One invite code is earned per $1M of lifetime perps volume, and codes materialize lazily — a batch of newly earned codes may take more than one read to appear (materializationPending). Codes are bearer secrets that grant perps trading access, so the list read is the one signed affiliate read: full header triple, message X-Timestamp + inviteCodes. Redemption is single-use and atomic — two callers racing on one code get exactly one win and one 409.The same release settles redemption semantics for callers who are already referred: redeeming moves the attribution to the invite code’s owner only when the code is what grants access — a caller who can already trade and has a referrer gets 409 and the code is not spent. A move is forward-only (the previous affiliate keeps commission already earned and stops accruing) and is confirmed asynchronously, so that path answers 202 rather than 200. The redemption response also no longer names the code’s owner, and GET /v1/affiliate/myReferrer redacts the same address — a referral binding is readable without disclosing the wallet behind it.
testnet-v1.8.0

New features

Subaccounts across the WebSocket surface. Subscriptions to the account-scoped channels — account, positions, orders, userFills, funding, accountTransferUpdates, and accountAttributeUpdates — take an optional accountIndex (0–9). Omit it for subaccount 0, which is what every client written before the field existed keeps getting. It is part of subscription identity: each subaccount is its own subscription with its own snapshot and stream, so one connection may hold several, and unsubscribe must repeat the same accountIndex — omitting it drops only subaccount 0. Every frame of an account-scoped channel now echoes accountIndex, including when it is 0, on subscribed, unsubscribed, degraded, and channel_data alike; that is what makes several subaccounts of one address demultiplexable on a single connection, since id alone is the master address and identical across all of them. Addresses in id come back lowercase whatever spelling was sent, so compare them case-insensitively, and an encoded core account id may be used instead — it already carries its own subaccount index, and supplying accountIndex alongside it is allowed only if the two agree. Supplying accountIndex on a channel that is not account-scoped is an error rather than an ignored field, as is a value outside 0–9: an out-of-range subaccount can never carry traffic, so accepting one would return a permanently silent subscription.

Updates

Per-account sequence numbers on positions and orders. Position and order rows carry sequenceNumber — the per-account sequence of the engine event that last wrote that row, the same counter as AccountUpdate.sequenceNumber — so a row can be ordered against account updates without inferring it from arrival order. The orders snapshot now carries lastSequenceId next to openOrders and recentClosedOrders, matching the positions snapshot, and streaming PositionUpdate envelopes stamp it too, so a client can tell exactly where its snapshot sits in the account’s event sequence and discard the updates it already contains. Both are WebSocket-side; REST omits sequenceNumber when unset.marginUsed reads by margin mode. On position rows the field now depends on the row’s marginMode. CROSS: the initial margin required at the current mark — |size| × mark × initial-margin fraction — so it moves as the mark moves. ISOLATED: the walled-off isolated-leg pool, which does not track IMR: it moves only when collateral actually moves, growing one-for-one with POST /v1/adjustIsolatedMargin. The full isolated-leg cash balance is derivable as marginUsed + borrowedCapital.
testnet-v1.7.10

Updates

New modify rejection reason MODIFY_SIZE_ALREADY_FILLED. Under total-size modify semantics — where the size on a POST /v1/modifyOrder is the order’s new total size, filled quantity included — a new total at or below the quantity already filled leaves nothing to rest. The original order is canceled (a CANCELED update precedes the rejection) and the modify is rejected with this reason. Use POST /v1/cancelOrder when the intent is to stop the unfilled remainder.
testnet-v1.7.7

Updates

Market filter on the remaining reads and account channels. An optional market — display ticker (BTC-USD, case-insensitive) or numeric market id (1) — now restricts GET /v1/prices, GET /v1/mids, GET /v1/positions, and GET /v1/leverages to a single market; an unresolvable value returns HTTP 400 rather than an unfiltered response. On prices and mids a filter naming an offline market returns an empty object, matching how the unfiltered response omits offline markets; an account with no position in the requested market returns empty positions, not a 404. The same filter is accepted on the WebSocket positions, orders, and userFills subscriptions, where it applies to the snapshot, the live frames, and the post-snapshot catch-up alike, so the baseline and the diffs always describe the same markets. It is part of subscription identity — one connection may hold several market-scoped views of the same account, and unsubscribe must repeat the market it subscribed with. Supplying market on any other channel is an error, not an ignored field. Frames on those three channels now carry market (the resolved ticker) so a client holding several views can demultiplex, and the subscribed / unsubscribed acks echo the filter. The WebSocket get RPCs take it too, on fills, orders, positions, leverages, mids, and prices.adjustIsolatedMargin is confirmed on the positions channel. Adding or removing isolated margin through POST /v1/adjustIsolatedMargin now emits a PositionUpdate on the positions channel, carrying the originating requestId so it can be correlated with the 202 ACK, and marginMode: ISOLATED. Every position row — snapshot and streaming — now includes marginMode (CROSS or ISOLATED), so the collateral mode of a position is readable without a REST round-trip.isolated and marginMode are always present on leverage entries. On the accountAttributeUpdates channel, type: "leverage" entries previously carried the margin mode only when a mode change was part of the same setLeverage request. Both fields are now always populated: in snapshot frames they reflect the persisted state, and in streaming frames the account’s margin mode after the triggering event, defaulting to CROSS if the mode lookup fails.
testnet-v1.7.3

New features

Adjust margin on an isolated position. POST /v1/adjustIsolatedMargin moves collateral between the cross bucket and an isolated-mode position’s leg. amount is a dollar decimal string — positive adds margin to the isolated leg, negative removes it, and zero returns HTTP 400; send dollars, not quote quantums. The (account, market) must already be in isolated mode with an open position. Like the other engine-confirmed writes it carries a lifecycle status separate from the HTTP code: APPLIED (200), ACK (202, forwarded but unconfirmed — watch the positions channel), or REJECTED (422) with a rejectReason of UNKNOWN_MARKET, INVALID_AMOUNT, NOT_ISOLATED, NO_OPEN_POSITION, or UNDERCOLLATERALIZED. The response echoes newIsolatedMarginQuoteBalance, also in dollars.Dead man’s switch. POST /v1/scheduleCancel arms, refreshes, or disarms a per-subaccount deadline; if it passes without a refresh the gateway fires cancelAllOrders for that subaccount. Pass an absolute epoch-microsecond time to arm or refresh, and omit it (or send null) to disarm. Lead time must be between 5 seconds and 5 minutes, and successful auto-fires are capped at 10 per UTC day per subaccount — past which the endpoint returns HTTP 429. A 503 means the switch is not armed (cancel path disabled or store unavailable), so retry rather than assuming coverage.

Updates

netDeposits semantics. The field on GET /v1/account and the accounts channel is documented as lifetime net deposits — cumulative inflows minus outflows across every applied account transfer, including deposits, withdrawals, internal and self transfers between your own account indices, and referral claims, with rejected transfers excluded. Unlike equity and freeCollateral it never moves with oracle prices; only a transfer changes it. Subtract it from equity for all-time PnL, on the same basis GET /v1/portfolio uses.
testnet-v1.7.1

Updates

status and market filters on order history. GET /v1/orders and GET /v1/openOrders accept an optional status alongside market, which separates orders resting on the book (OPEN) from TPSLs parked on the untriggered book (UNTRIGGERED). Values are OPEN, UNTRIGGERED, FILLED, CANCELED, REJECTED, LIQUIDATED, and ADL, case-insensitive; status accepts either a JSON array (["OPEN","CANCELED"]) or a comma-separated string ("OPEN,CANCELED"), and an unrecognized value returns HTTP 400. It matches an order’s current status, not any status it held earlier. Both filters apply before the row cap, so a filtered page still carries up to limit orders. The same filters are available on the WebSocket orders RPC, where they apply to both the openOrders and recentClosedOrders halves of the result.from/to on funding are microseconds. The bounds on GET /v1/funding and GET /v1/fundingRates are epoch microseconds, matching the unit of the timestamp field each response reports — so a value read off one page is a valid bound for the next. The spec previously described them as epoch milliseconds; a millisecond value is now far below the accepted minimum.WebSocket error codes completed. Ten codes the gateway already returned were missing from the published enum: TimestampReused, ModifiesArrayEmpty, ModifiesArrayTooLarge, RateLimited, and AddressNotOnWhitelist on post, and MarketOffline, GetLeveragesFailed, GetRateLimitFailed, LeverageHandlerUnavailable, and RateLimitHandlerUnavailable on get. No behavior change — clients exhaustively matching on the enum can now recognize all of them.
testnet-v1.6.0

New features

Batch order modification. POST /v1/batchModifyOrders reprices or resizes up to 100 open orders in one request. Every row must share the same (address, accountIndex) — a batch is scoped to a single subaccount — and each row carries its own signature over the same typed canonical modify payload (op 3) a standalone POST /v1/modifyOrder signs, so the signed bytes are identical either way. Like the other batch routes it authenticates per element rather than with a verified envelope signature, and failures are per-row: a row rejected for validation or signature reasons comes back with status: ERROR and an error message while the remaining rows still reach the matching engine. The same operation is available over WebSocket.Isolated margin mode. POST /v1/setLeverage accepts an optional isolated flag that sets the margin mode for a (account, market) alongside the leverage — true for isolated, false for cross, omitted to leave the mode unchanged. Switching cross → isolated is rejected with HAS_OPEN_POSITION when a position is already open in that market; isolated → cross and no-op changes are always accepted. GET /v1/leverages now returns the margin mode (isolated / marginMode) next to the effective leverage for every market, and the accountAttributeUpdates channel folds the margin-mode outcome into the same entry via marginModeStatus and marginModeRejectReason, including on the leverageReject entry emitted when the engine refuses a request.

Updates

Modify an order by client id. ModifyOrderRequest accepts clientId as an alternative to orderId, resolved engine-side against the account’s client-id index — so an order can be modified before the place response carrying its server-generated id has arrived. Supply exactly one: setting both is rejected, and so is setting neither.side filter on order and fill history. GET /v1/orders and GET /v1/fills accept an optional case-insensitive side (BUY / SELL) to restrict results to a single trade direction. Omit it to return both sides; an unknown value returns HTTP 400.Snapshot size control on userFills. Subscribing to the userFills channel accepts an optional nFills (1–500, default 500) that bounds the initial snapshot. It is ignored on other channels, and live channel_data frames are unaffected.
testnet-v1.4.8

Updates

Market filter on funding payments. GET /v1/funding accepts an optional market to restrict results to a single market, given as either the display name (e.g. BTC-USD, case-insensitive) or the numeric market id. Omit it to return every market; an unresolvable value returns HTTP 400.
testnet-v1.4.7

New features

Scoped API keys and API-key-signed withdrawals. GET /v1/apiKeys entries carry an optional permissions array describing scopes granted beyond the default. Every key can read and trade; the withdraw scope additionally authorizes POST /v1/withdraw using the X-API-Key / X-Timestamp / X-Signature header triple with an Ed25519 signature over the ordersign WithdrawV1 typed canonical payload (op 5), in which case the body signature field is ignored. The key must be bound to exactly the requested (ethereumAddress, accountIndex). Replay protection matches the wallet-signed mode: the X-Timestamp drift window plus a single-use nonce per (ethereumAddress, accountIndex), with HTTP 409 on reuse. The scope is grantable only through the operator’s provisioning flow — keys created via the public POST /v1/createApiKey are always trade-only and are rejected with HTTP 403. The original wallet-signed EIP-712 mode is unchanged, and withdraw-to-self remains the only supported destination on both modes.
testnet-v1.4.6

Updates

GET /v1/apiKeys spans every subaccount by default. GET /v1/apiKeys has no default accountIndex — omitting it lists the keys of every subaccount, each entry tagged with the accountIndex it belongs to, so a listing can be grouped client-side without one request per subaccount. Pass accountIndex to scope the listing to a single subaccount. Unlike other account-scoped reads, an omitted value is not the same as accountIndex=0, and a non-integer or out-of-range value returns HTTP 400 rather than silently falling back to 0. The response is all-or-nothing across subaccounts: an unreadable subaccount surfaces as HTTP 500 rather than a short list that would look like a revoked key.
testnet-v1.4.5

Updates

Market and role filters on order and fill history. GET /v1/orders and GET /v1/fills accept an optional market, and GET /v1/fills additionally accepts a case-insensitive role to restrict results to a single liquidity role. Market filters across the API — including GET /v1/markets — now accept either the display name (case-insensitive) or the numeric market id, and an unresolvable value returns HTTP 400.Multiple orderbook aggregations per market on one connection. A connection may subscribe to the l2Orderbook channel more than once for the same market as long as each subscribe uses a distinct (sigFigs, roundStep) pair. subscribed, channel_data, and unsubscribed frames echo those fields — omitted for full-precision views — so a client holding several views of one market can demux them. Unsubscribing must repeat the same pair to drop one view without affecting the others.
testnet-v1.4.3

New features

API-key replay protection & subaccount scoping. POST /v1/createApiKey and POST /v1/revokeApiKey accept an optional nonce (single-use per (address, accountIndex)) for replay protection and an accountIndex (0–9) that scopes the key to a subaccount. Both are bound into the EIP-712 signature: a non-zero accountIndex must use the new accountIndex-bearing CreateApiKey/RevokeApiKey type, and including a nonce requires the combined type that binds both. Send the nonce as nanoseconds since the Unix epoch (accepted within −48h/+24h; a legacy opaque UUID also works); a replayed nonce returns HTTP 409. Index 0 still accepts the original index-less type and the legacy EIP-191 fallback during the migration window.

Updates

New order-rejection reason POSITION_SIZE_CAP_EXCEEDED. Orders, modifies, or fills that would exceed a market’s per-market position notional cap are rejected with POSITION_SIZE_CAP_EXCEEDED — distinct from UNDERCOLLATERALIZED, since a fully funded account can still hit it.
testnet-v1.4.2

Breaking changes

Time-window bounds are now microseconds. The from/to query parameters on GET /v1/openOrders, GET /v1/orders, GET /v1/fills, GET /v1/trades, and GET /v1/accountTransferUpdates are now epoch microseconds, matching the createdAt / updatedAt / timestamp precision these endpoints already report — so a value read from one page is a valid bound for the next with no conversion. Millisecond- or second-scale values are rejected with HTTP 400 (the server requires at least 1e14); a millisecond bound read as microseconds lands in 1970 and silently returns nothing. Clients that previously sent milliseconds must update.
testnet-v1.4.1

Updates

GET /v1/openOrders is now bounded and paginated. GET /v1/openOrders accepts limit (1–1000; default and maximum both 1000, larger values silently clamped) plus from / to (epoch microseconds) to bound the window on createdAt. Responses stay newest-first; page backward by sending the oldest createdAt you received as the next request’s to, deduplicating by orderId since the inclusive bound overlaps page edges. An account can hold up to 10,000 live orders, so more than one page may be needed.
testnet-v1.3.9

Breaking changes

Deprecated *Bps fee-tier aliases removed. The makerFeeBps/takerFeeBps fields on GET /v1/feetiers, GET /v1/account/stats, and feeTierConfig entries on exchangeAttributeUpdates — along with the spot schedule’s maker_fee_bps/taker_fee_bps — are gone, completing the ppm rename announced in testnet-v1.2.31. Use makerFeePpm/takerFeePpm (and maker_fee_ppm/taker_fee_ppm); the values are unchanged.
testnet-v1.3.8

New features

Orderbook price aggregation. GET /v1/l2OrderBook/{market} and the l2Orderbook channel accept an optional sigFigs (2–5) to bucket price levels to that many significant figures, plus roundStep (1, 2, or 5) to refine the finest bucket when sigFigs is 5. Bids round down and asks round up so the displayed spread is never tighter than the true book, merged sizes are summed, and aggregation is applied before nLevels truncation. Omit sigFigs for full precision.

Updates

Order-size bounds on markets. GET /v1/markets and the markets channel add minOrderSize and maxOrderSize (base-asset units). maxOrderSize is a per-order security gate rather than a dust filter — reduce-only orders are not exempt.
testnet-v1.3.7

Updates

Explicit RTH-transition events on marketAttributes. The marketAttributes channel’s boundEvent adds exitRth / enterRth for Regular Trading Hours boundary crossings, and is now present on every delta entry — only snapshots omit it. boundSide is likewise always present on deltas (null on RTH transitions and VWAP seals).Portfolio PnL rebased per timeframe. pnlHistory on GET /v1/portfolio now rebases each timeframe so its first point is 0 — every point is the trading + funding PnL earned since the start of that timeframe, and lifetime PnL is the last point of the all timeframe. The curve still does not jump on deposits or withdrawals.
testnet-v1.3.6

New features

Off-hours market attributes over WebSocket. New marketAttributes channel streams per-market Regular Trading Hours / off-hours trading-band state for every online market — isOutsideRth, the sealed currentSettlementPrice anchor, both current trading-band edges and their next-level edges, and per-side expansion-zone state with its clocks. It is a global channel (no id): a full per-market snapshot on subscribe (isSnapshot: true), then a single-market update on each RTH boundary crossing, VWAP seal, and off-hours bound event — each carrying that market’s complete post-event block plus a timestamp and marketSequenceNum. Fields that do not apply are null (24/7 crypto markets are included with isOutsideRth: false and all band fields null). Supersedes the marketAttributes entry variant on exchangeAttributeUpdates.
Documentation

Updates

Docs default to mainnet. The API playground and the curl / Python / JavaScript code samples throughout the API reference now target the production host — https://api.arcus.xyz (REST) and wss://api.arcus.xyz/v1/ws (WebSocket) — instead of testnet. Testnet (api.testnet.arcus.xyz) remains fully available and is still selectable from the server dropdown on every endpoint and channel page; the two environments share identical paths, payloads, and signing, so a sample runs unchanged against either by switching the host. This supersedes the earlier note (below) that samples and the playground targeted testnet.
testnet-v1.3.5

Updates

Forced closures are marked on fills. Fill rows add a liquidation object — method (LIQUIDATION or ADL) plus liquidatedUser — present on the liquidated account’s leg of a liquidation and the deleveraged counterparty’s leg of an auto-deleverage; absent on voluntary fills. The marker is persisted, so GET /v1/fills and userFills snapshots return it too, and it is the supported way to detect forced closures (the liq: order-ID prefix is an internal detail). On the liquidated leg, fee carries the liquidation penalty paid to the insurance fund and closedPnl reads "0" by design — the realized loss is already reflected in netQuoteBalance on the accompanying account update.
testnet-v1.3.3

New features

Account transfer events over WebSocket. New accountTransferUpdates channel streams deposits, withdrawals, internal transfers, and referral claims for an account: a newest-first snapshot on subscribe, then one event per transfer as the engine applies it. Amounts are decimal strings in quote currency, and globalSequenceId gives strict ordering. The REST equivalent is GET /v1/accountTransferUpdates.Predicted funding over WebSocket. New predictedFunding channel streams the predicted next-hour funding rate per market as a {market, rate1h} payload, refreshed each time the funder recomputes the prediction. Unlike most channels, payloads are not wrapped in an isSnapshot envelope.

Updates

Subaccount selector on all account-scoped reads. The optional accountIndex query parameter (0–9, default 0) previously accepted only by GET /v1/fills now applies across account-scoped endpoints: GET /v1/account, /v1/positions, /v1/openOrders, /v1/orders, /v1/order/{orderId}, /v1/funding, /v1/accountTransferUpdates, /v1/portfolio, /v1/rateLimit, /v1/leverages, and /v1/apiKeys. Values above 9 return 400.Faster orderbook snapshots. The l2Orderbook full-snapshot cadence tightened from ~500 ms to ~200 ms.
testnet-v1.3.1

Updates

24-hour high/low on markets. GET /v1/markets and the markets channel add high24h and low24h — highest and lowest transaction price over the trailing 24-hour window, computed from closed 1-minute candles with at least one trade and omitted when no trades occurred in the window.
testnet-v1.2.31

Updates

Fee-tier fields renamed to ppm. makerFeeBps/takerFeeBps become makerFeePpm/takerFeePpm in the fee-tier shape returned by GET /v1/feetiers, GET /v1/account/stats, and feeTierConfig entries on exchangeAttributeUpdates; the spot fee schedule likewise renames maker_fee_bps/taker_fee_bps to maker_fee_ppm/taker_fee_ppm. The values were always parts-per-million despite the old names. The *Bps fields remain as deprecated aliases (identical values) for one release cycle — migrate to the *Ppm names now.
testnet-v1.3.0

Breaking changes

Testnet withdraw/transfer signing domain rotated. The July 22 testnet reset rotated the BridgeVault verifyingContract for POST /v1/withdraw and POST /v1/transfer to 0x9a6d3499149fea853efe775a3577701539054eaf; signatures against the previous address are rejected with 401. This address rotates on every testnet reset — read the current value from the withdraw endpoint’s per-environment table. The funding guide contract addresses rotated in the same reset.

Updates

Perp candle timestamp bounds declared in the schema. GET /v1/candles from/to (Unix microseconds) now declare minimum: 1e14, matching what the handler always enforced.
testnet-v1.2.6

Updates

API key create/revoke signing migrates to EIP-712. POST /v1/createApiKey and POST /v1/revokeApiKey are now authenticated by an EIP-712 typed-data signature (eth_signTypedData_v4) instead of an EIP-191 personal_sign. Both schemes are accepted during the migration window; EIP-191 is deprecated and will be rejected once the window closes. Always send validUntil explicitly and sign that value — omitting it makes the server verify against its own default. See each endpoint description for the domain, types, and signing examples.Spot candle timestamp bounds declared in the schema. GET /v1/api-meta/candles from/to (Unix seconds) declare the [1, 1e11) window, rejecting millisecond-scale values.
testnet-v1.2.3

New features

Internal transfers between subaccounts. New POST /v1/transfer moves collateral between two account indexes of the same wallet — in v0 there is no cross-wallet recipient. The request is signed with an EIP-712 typed-data signature over the Transfer payload (eth_signTypedData_v4) and carries a single-use nanosecond-timestamp nonce for replay protection (a repeated nonce returns 409). amount is a quote-quantum integer string (1e9 = $1); unlike withdrawals it never settles on-chain, so it is not constrained to collateral-base-unit multiples. Acceptance is asynchronous: the response carries status: PENDING and a transferId, with the terminal outcome delivered on the account transfer update stream — insufficient free collateral rejects there with REJECTED_INSUFFICIENT_COLLATERAL.Per-market open-interest caps. GET /v1/markets and the markets WebSocket channel add openInterestCap — the operator-set maximum open interest as a USD-notional decimal string (present only while a cap is active). While a market is at its cap, the engine rejects OI-increasing fills with the new rejection reason OPEN_INTEREST_CAP_EXCEEDED; OI-neutral and OI-reducing trades (closes, and opener-vs-closer pairings) still match. Fills executed before the halt stand, and the cap clears as open interest falls or the operator raises it.

Updates

Signed withdrawals are single-use. POST /v1/withdraw now rejects a replayed (ethereumAddress, accountIndex, nonce) with 409 — resubmitting an identical signed body (or any body reusing the same nonce) no longer queues a second withdrawal. Use a fresh nonce for each new withdrawal; the recommended nonce is the current time in nanoseconds since the Unix epoch.
testnet-v1.2.2

Updates

API keys are scoped to (address, publicKey). An Ed25519 public key is globally unique across accounts: POST /v1/createApiKey returns 409 Conflict when the publicKey is already registered to a different account (including expired-but-unrevoked keys), and only the owning account may register or renew it. POST /v1/revokeApiKey returns 404 when the key is not registered to the caller’s account — including cross-account revoke attempts — with no side effects.
testnet-v1.2.1

New features

Sectioned account stats. GET /v1/account/stats is now sectioned so clients fetch only what they need via the include query parameter: feeTier (the current fee tier — cheap, right shape for frequent fee-rate polling) and volumes (notional fill volume and fees paid over the 14-day fee-tier rolling window and all-time — backed by analytics storage, fetch on demand). The volumes section also accepts opt-in fixed windows via windows=24h,7d,30d.Market filter on fills. GET /v1/fills adds an optional market query parameter to restrict fill and trade history to a single market, alongside the existing from/to time bounds and accountIndex subaccount selector.
testnet-v1.2.0

Breaking changes

Withdraw EIP-712 signing domain rotated; production domain published. The BridgeVault verifyingContract for POST /v1/withdraw changed on staging (0xfcb43af23e80dbbe7d951af49aa4eefb4eff8c2c) and testnet (0x317253c5c134c3ac60e84c4ca069c9f588030480) — withdrawal signatures produced against the previous addresses are rejected. The production domain is now published: chainId 4663, verifyingContract 0x14b107cf534239c59571b066cb6497a321da897c.

Updates

Modify order is no longer marked “coming soon”. The stale caveat claiming POST /v1/modifyOrder returns 501 Not Implemented is removed — the endpoint has been live for some time. The docs now also spell out the queue-priority contract: a modify is applied in place (keeping queue priority) only when it leaves the price unchanged and reduces size; any price move or size increase is an atomic cancel + replace that loses priority. On the orders WebSocket channel a non-crossing modify arrives as a single update; a crossing modify arrives as a fill followed by a PLACED (or REJECTED) — no separate cancel/place event pair is emitted.goodTilTime is required on every order — the schema now says so. The order schema previously required goodTilTime only for resting time-in-forces (GTT, ALO) and described it as “ignored” for IOC/FOK; the API has always rejected orders without it. It is now documented as unconditionally required on POST /v1/placeOrder, the batch variants, and the WebSocket order payloads: for IOC/FOK it acts as a mandatory replay-protection timestamp, and it must be at least one month in the future.Time-in-force: submit GTT, read GTC. Order submissions must use GTT (Good Till Time) for resting orders, but order reads — REST order queries and the orders WebSocket channel — currently report resting orders as GTC, the legacy name for the same bucket. A new TimeInForceResponse schema documents the read-side enum; treat GTC and GTT as equivalent when reading.modifyOrder signing payload documented in full. The typed canonical payload for modifyOrder now shows its complete field set — {"ad","ai","c","ct","g","id","m","op":3,"p","q","r","s","t","v"}. id is always required, and g/r/s/t echo the resting order’s goodTilTime (in nanoseconds), reduceOnly, side, and time-in-force. The modify request body now also requires reduceOnly and goodTilTime to be echoed explicitly (a differing goodTilTime performs a cancel-replace with the new expiry).Subaccount authorization on order writes. The 403 responses on POST /v1/placeOrder, POST /v1/cancelOrder, the batch variants, and POST /v1/modifyOrder now also cover the case where accountIndex does not match the API key’s authorized subaccount.
testnet-v1.2.0

Breaking changes

Off-hours trading-band fields reshaped. On GET /v1/markets and the markets WebSocket channel, the off-hours band is now reported as actual USD price boundaries rather than multiplier strings. currentTradingBound / nextTradingBound are removed; use upperTradingBound / lowerTradingBound (plus nextUpperTradingBound / nextLowerTradingBound) and the new per-side expansion-zone state — isUpperInExpansionZone / isLowerInExpansionZone, upperZoneEnteredAt / lowerZoneEnteredAt, and upperExpectedExpansionAt / lowerExpectedExpansionAt. Each side’s band now expands independently on the 0.5× ladder.Rejection reason consolidated. ORDER_WILL_TAKE_LIQUIDITY_DURING_MARKET_HALT and PRICE_WILL_EXCEED_MAXIMUM_OUTSIDE_RTH_TRADING_BOUND are deprecated (no longer emitted) and replaced by a single FILL_WILL_EXCEED_TRADING_BOUND, covering crossing takers, crossing modifyOrder cancel-replaces, triggered TPSLs, and placements that would rest reachable beyond the band.

New features

Maximum order size enforced. POST /v1/placeOrder, POST /v1/modifyOrder, and the batch variants now reject an order whose quantity exceeds the market’s maxOrderSize (see GET /v1/markets) with OrderSizeTooLarge. Reduce-only orders are not exempt.Market-attribute events over WebSocket. The exchangeAttributeUpdates channel now emits marketAttributes entries carrying per-market Regular Trading Hours and off-hours band events: RTH boundary crossings (isOutsideRth), VWAP settlement seals (sealedVwapSettlementPrice), and expansion-zone / band-expansion events (boundEvent: expansionZoneEntered, expansionZoneExited, tradingBoundExpanded).

Updates

Candle prices are oracle-derived. GET /v1/candles open / high / low / close are derived from the market’s oracle price feed, not executed trades. volume, takerBuyVolume, the notional volumes, and tradeCount remain trade-derived statistics for the bucket.
testnet-v1.1.98

Breaking changes

reduceOnly no longer requires IOC or FOK. POST /v1/placeOrder and POST /v1/modifyOrder now accept reduceOnly: true with any timeInForce — the previous constraint forcing reduce-only orders to be IOC or FOK is removed. Reduce-only position semantics are enforced regardless of TIF, so a resting reduce-only order is now valid.

New features

Rolling fees-paid on account stats. GET /v1/account/stats adds rollingFeesPaid — perps trading fees paid over the 14-day fee-tier rolling window (quote quantums, 1e9 = $1), the same window as rollingVolume. It’s computed from an hourly rollup, so it can trail live fills by up to the current partial hour, and reads 0 if that rollup is temporarily unavailable.
Mainnet

New features

Lightweight referral-code lookup. New GET /v1/affiliate/code returns just { address, code, isAffiliate } from a single point read — none of the volume, commission, or fee-tier enrichment that GET /v1/affiliate/info performs. It’s meant for UI surfaces that only need the code (an “Invite Friends” / copy-referral-link control) and may poll every session. Public — no X-API-Key, no signature. “Not an affiliate” is a valid empty state served as 200 with code: "" and isAffiliate: false, never a 404, so callers don’t have to overload the status code. Initially mainnet-only; available on both environments since mid-July 2026.
testnet-v1.1.98

Breaking changes

Market category values are now upper-case and add CRYPTO. The category field on GET /v1/api-meta/overview and GET /v1/api-meta/spot/overview now returns EQUITIES, COMMODITIES, INDICES, or CRYPTO, replacing the previous lower-case stocks / commodities / indices. Still omitted for underlyings outside the classified universe.

New features

Per-subaccount rate-limit snapshot on write responses. POST /v1/placeOrder, POST /v1/batchPlaceOrders, POST /v1/cancelOrder, POST /v1/batchCancelOrders, POST /v1/cancelAllOrders, and POST /v1/modifyOrder now return a rateLimit object (poolorder or cancel — and remaining tokens after the request) on both REST and WebSocket, so clients can track their remaining budget without an extra call. remaining can be 0 or negative while the request still succeeds when the account is on the drip throttle; -1 is a sentinel meaning the per-subaccount layer was not enforced for this request.clientId echo on rate-limit rejections. The 429 body now echoes the request’s clientId (single-order endpoints) or clientIds (batch endpoints, positionally aligned with the submitted array), so a client firing concurrent requests can correlate the rejection to a specific order or batch.New modify rejection reason. MODIFY_WOULD_CROSS_OUTSIDE_RTH_TRADING_BOUNDARY — a non-crossing modifyOrder reprice rejected because the new price violates the active off-hours trading band. Unlike PRICE_WILL_EXCEED_MAXIMUM_OUTSIDE_RTH_TRADING_BOUND (the crossing cancel-replace path, which removes the original), the original order stays resting on the book unchanged.Rejected setLeverage is now observable on WebSocket. The accountAttributes channel adds a streaming-only leverageReject entry — the REJECTED half of the setLeverage lifecycle. It carries the rejectReason (UNDERCOLLATERALIZED, INVALID_LEVERAGE, or UNKNOWN_MARKET) and the originating requestId for correlation; an applied change still arrives as a leverage entry.

Updates

Deterministic market ordering documented. GET /v1/markets now documents that markets are returned sorted by ascending marketId, and the mids map on GET /v1/mids is ordered by ascending marketId and includes only ONLINE markets (OFFLINE markets are omitted).Spot candles stream at every resolution. The api-meta candles WebSocket channel aggregates each resolution (1m through 1w) and a subscription selects one via the SYMBOL/TIMEFRAME id (e.g. AAPL/5m) — previously only 1m was documented.
testnet-v1.1.96

Breaking changes

Position-tiered margin fields removed. GET /v1/api-meta/markets and the markets WebSocket channel no longer return transferMarginFraction, incrementalInitialMarginFraction, incrementalPositionSize, baselinePositionSize, or maxPositionSize. Initial margin is no longer scaled by position-size brackets in the published market schema; initialMarginFraction, maintenanceMarginFraction, and the off-hours variants remain.minOrderSize and maxOrderSize removed. The same market reads drop minOrderSize and maxOrderSize, and minOrderSize is no longer a required field. Per-market order sizing is now expressed through minOrderNotional (the $5 minimum-notional floor introduced in testnet-v1.1.93) and stepSize.
testnet-v1.1.93

Breaking changes

All-traders leaderboard replaces the affiliate volume leaderboard. GET /v1/affiliate/volumeleaderboard (getVolumeLeaderboard) is gone, replaced by GET /v1/leaderboard (getTraderLeaderboard). A new sortBy query param (volume, pnl, or fees; default volume) chooses the ranking column, and every row now carries volume, feesPaid, and pnl (realized only) together, computed in one query so the three columns are always mutually consistent. The window (all/30d/24h, default 30d) and limit (max 100, no cursor) semantics are unchanged.Notification timestamps are now decimal strings. On GET /v1/api-meta/notifications, createdAtNs is now a string — the value exceeds 2^53 and a JSON number would lose precision in JS clients. Pass it back verbatim as the before_ns cursor (also now a decimal-string query param) and inside ids[].created_at_ns on :markSeen; a truncated value targets the wrong row. :markSeen still accepts a bare number for backward compatibility.Minimum order notional enforced. POST /v1/placeOrder and POST /v1/batchPlaceOrders now reject position-opening orders whose notional (quantity × price) is below $5 with InvalidRequest. Reduce-only orders (including TPSLs) are exempt. The per-market floor is published as minOrderNotional on GET /v1/api-meta/markets.API key keyName removed. POST /v1/createApiKey no longer accepts or returns the optional keyName label.

New features

Deposit & withdrawal notifications. The notification inbox now surfaces deposit and withdrawal events through a new NotificationTransferPayload (subaccountIdx, amount, netQuoteBalance, operationId). These events are not market-scoped, so the enclosing marketId is 0.Off-hours trading-band fields. GET /v1/api-meta/markets and the markets WebSocket channel now expose currentSettlementPrice, currentTradingBound, and nextTradingBound for equity-class markets while outside regular trading hours (omitted in-RTH and for 24/7 crypto markets).Lifetime volume & fees on the fee-tier read. GET /v1/feetiers now returns lifetimeVolume and lifetimeFeesPaid alongside the existing 14-day rollingVolume.

Updates

Open interest is now populated. openInterest on GET /v1/api-meta/markets and the markets WebSocket channel now reports the total size of open long positions (equal to total short, in base-asset units), refreshed from a periodic snapshot, instead of the previous placeholder "0".Market category on overview reads. GET /v1/api-meta/overview and GET /v1/api-meta/spot/overview add a category field (stocks, commodities, or indices) for classified equity-class underlyings.
Mainnet live

New features

Mainnet is live. The production API is now serving at https://api.arcus.xyz (REST) and wss://api.arcus.xyz/v1/ws (WebSocket), selectable from the server dropdown on every endpoint page. Testnet (api.testnet.arcus.xyz) remains available, and the two environments share identical paths, payloads, and signing — only the host differs. The code samples and API playground throughout the docs continue to target testnet. See the API introduction.
testnet-v1.1.91

Updates

Minimum withdrawal size enforced. POST /v1/withdraw now rejects amounts below the collateral currency’s minimum with 400 — e.g. validation error on field 'amount': must be at least 1000000000 quote quantums (1e9 quote quantums = $1). Amounts must also be exactly representable in collateral base units.compliance address section now conditional. GET /v1/compliance returns the address screening section only when the ?address= query param is supplied; geo is always present. address is no longer a required response field.Spot price & candle WebSocket payloads documented. The api-meta prices and candles WebSocket channels now have published payload schemas (SpotPrices / SpotPrice and SpotCandlesSubscribed / SpotCandlesChannelData) covering both the subscribe snapshot and the per-tick channel_data frames.
testnet-v1.1.90

Breaking changes

Order time-in-force rules tightened. New per-order-type timeInForce constraints, enforced at request validation:
  • Every order must include goodTilTime (epoch microseconds) set at least one month in the future — now required even for IOC orders, which previously ignored it. A missing value is rejected with validation error on field 'goodTilTime': is required.
  • MARKET orders must use IOC. GTT, FOK, and ALO are rejected with validation error on field 'timeInForce': must be IOC for MARKET orders.
  • TPSL orders: LIMIT TPSL legs must use GTT; MARKET TPSL legs must use IOC. (TPSL legs must also be reduceOnly, and are placed via batchPlaceOrders groupings.)
testnet-v1.1.89

New features

Server time. GET /v1/time returns the current server time — useful for aligning the nanosecond signing timestamp with the gateway’s ±30s drift window.
testnet-v1.1.82

Breaking changes

Order signing moved to the ordersign typed canonical payload. placeOrder, cancelOrder, and modifyOrder — and each element of batchPlaceOrders / batchCancelOrders — now sign a compact, key-sorted JSON payload built from the parsed request: the payload object is the Ed25519 message, with no timestamp + action prefix. The timestamp is carried as the ct field (it must equal X-Timestamp), and price/size are signed as integer ticks/quantums derived from the market’s tickSize / stepSize. The previous X-Timestamp + action + canonicalJSON(body) scheme is now rejected with 401 for these endpoints. cancelAllOrders, setLeverage, and WebSocket authentication keep the legacy message. See Authentication.GTC replaced by GTT. The timeInForce enum is now GTT, IOC, FOK, ALO. Resting orders (GTT, ALO) require goodTilTime (epoch microseconds) set at least one month in the future at the time the order is processed; nearer or missing values are rejected.Withdrawals now use EIP-712 typed data. POST /v1/withdraw authenticates with an eth_signTypedData_v4 signature over a Withdraw typed payload (domain and types in the endpoint reference) instead of the previous SHA-256 ECDSA canonical message.Market orders require a protective price bound. A MARKET order’s price must be within 10% of the current mark price (TPSL market orders: within 10% of the trigger price), or the order is rejected. With this bound, market orders behave like marketable limit orders.

Updates

New order rejection reason. PRICE_WILL_EXCEED_MAXIMUM_OUTSIDE_RTH_TRADING_BOUND is added to the RejectionReason set delivered on the orders WebSocket channel — emitted when a resting order’s price would breach the maximum off-hours trading bound once the current regular-trading-hours session ends.
Endpoint migration

Breaking changes

API base URLs moved to api.testnet.arcus.xyz. REST is now https://api.testnet.arcus.xyz and WebSocket wss://api.testnet.arcus.xyz/v1/ws/. The previous hostnames are being retired — update any saved base URLs, SDK configs, and clients at your earliest convenience to avoid disruption. Paths and payloads are unchanged. See the API introduction.
testnet-v1.1.79

New features

Spot market overview REST endpoint. GET /v1/api-meta/spot/overview returns the curated spot market universe in source order, with each entry augmented by Market Cap and logo_url from the latest stored market metadata profile when available. Public — no X-API-Key or signature required.
testnet-v1.1.78

Breaking changes

Candles pagination replaced. GET /v1/candles no longer accepts limit. A request must now pass to — the upper bound of the window as a Unix microsecond timestamp (seconds- or milliseconds-scale values are rejected) — and may scope the lower bound with either countback (number of closed bars counting back from to) or from (a microsecond lower bound); from and countback are mutually exclusive. A request without to now returns 400.volume30d renamed to rollingVolume. GET /v1/account/stats and the affiliate commission and claim schemas now report notional fill volume under rollingVolume, measured over the fee-tier rolling window rather than a fixed trailing 30 days. Update any client that reads volume30d.

Updates

New order rejection reasons. The RejectionReason set delivered on the orders WebSocket channel adds OPEN_ORDER_CAP_EXCEEDED, ORDER_NOT_FOUND, ORDER_NOT_FOUND_FOR_MODIFY, MODIFY_CHANGED_IMMUTABLE_FIELD, MODIFY_ZERO_SIZE, and ORDER_WILL_TAKE_LIQUIDITY_DURING_MARKET_HALT.Market asset name in metadata. Market metadata responses now include fullAssetName (e.g. Bitcoin) when a canonical name is configured for the market.
testnet-v1.1.75

Breaking changes

Unified request signing. REST and WebSocket now share one signing message: X-Timestamp + action + canonicalJSON(body), where action is the canonical operation name — the REST path’s final segment or the WebSocket request type (e.g. placeOrder, cancelOrder). The HTTP method and the /ws/v1/ path prefix are no longer part of the signed message; re-sign with the new message before sending or the request is rejected with 401 invalid signature. Batch methods sign each element over its singular action (e.g. placeOrder for each order in batchPlaceOrders) with one shared timestamp. The cutover also invalidates API keys registered before it — re-register via POST /v1/createApiKey (EIP-191 registration is unchanged). See Authentication.
testnet-v1.1.74

Breaking changes

Protected requests now require nanosecond timestamps. The signing timestamp — X-Timestamp for REST, timestamp for WebSocket order methods — must now be Unix time in nanoseconds as a decimal string (e.g. 1713825891591000000), not milliseconds. Millisecond or second epochs are rejected with 401 Unauthorized. Update any client that builds the signing message before re-signing. See Authentication.

Updates

User-facing timestamps are now microseconds. Response time fields — candle openTime, funding payment times, and order placement/update times — are emitted in Unix microseconds for consistent precision across the API.
testnet-v1.1.70

New features

Market overview REST endpoint. GET /v1/api-meta/overview returns a consolidated per-market overview keyed by base asset, so clients can fetch headline market data in a single call.Volume leaderboard REST endpoint. GET /v1/affiliate/volumeleaderboard returns the top addresses ranked by signed-notional fill volume over a rolling window — all, 30d, or 24h (default 30d).Referral commission rate schedule. GET /v1/commissionrates returns the referral commission rate schedule used to compute affiliate payouts on each fill.
testnet-v1.1.69

New features

Push notification device tokens. Register an Expo push token for the calling wallet with POST /v1/api-meta/notifications/tokens so the notifications consumer can deliver a push when a matching event (resting fill, liquidation, TP/SL trigger) lands, and remove it with DELETE /v1/api-meta/notifications/tokens.
testnet-v1.1.65

New features

Rate-limit usage REST endpoint. GET /v1/rateLimit returns the state of both per-subaccount throttle pools (order and cancel), so clients can self-pace and see which limit is currently constraining them.Withdrawals REST endpoint. POST /v1/withdraw submits a withdrawal of collateral to the chain.Market metadata REST endpoints. GET /v1/api-meta/markets returns curated reference data — company profile, branding, headline financials, and TradingView chart identifiers — for one or all markets. Branding icons and market capitalizations are served by GET /v1/api-meta/overview, which folds in what were briefly separate icons / marketCaps projections.Notifications REST endpoints. List the most recent notifications for an address (newest-first) with GET /v1/api-meta/notifications, and mark them read with PATCH /v1/api-meta/notifications:markSeen — either an explicit list of (created_at_ns, notification_id) pairs, or the most recent limit rows for the wallet via all=true.Referral code availability. GET /v1/affiliate/codeAvailable returns { code, available } for a single referral code string.
testnet-v1.1.56

New features

Fee tier table REST endpoint. GET /v1/feetiers returns the full fee tier table, sorted ascending by level (0=Base through 4=Platinum) — the maker/taker fee BPS for each tier and the 30-day notional volume threshold required to reach it.Exchange attribute updates WebSocket channel. Subscribe to exchangeAttributeUpdates for exchange-wide state, discriminated by entry type. The current type, feeTierConfig, sends the full fee tier table on subscribe and a fresh replacement whenever an operator updates it — the streaming counterpart to GET /v1/feetiers.
testnet-v1.1.54

New features

Account attribute updates WebSocket channel. Subscribe to accountAttributeUpdates for live per-account state — effective leverage per market and the account’s current trading fee tier — discriminated by entry type ("leverage" or "feeTier"). On subscribe the server sends one leverage entry per market plus, when available, one fee tier entry; updates stream a single-entry delta for whichever attribute changed.Leverages REST endpoint. GET /v1/leverages returns the effective leverage for (address, accountIndex) across every market, sorted by ascending marketId. Each entry reflects the user’s override (set via POST /v1/setLeverage) when one exists, otherwise the market default.Account stats REST endpoint. GET /v1/account/stats returns 30-day rolling notional fill volume and the current trading fee tier (level + BPS) for any Ethereum address.

Updates

Affiliate endpoints moved. All /v1/api/affiliate/* paths are now under /v1/affiliate/* — the legacy /api/ segment has been dropped. Update any clients that hard-coded the old prefix. Operation IDs and request/response schemas are unchanged.
testnet-v1.1.47

New features

Trades REST endpoints. Query recent public trades for a market with GET /v1/trades, or fetch a single trade by ID with GET /v1/trade/{tradeId}.Funding payments — REST and WebSocket. Track per-account funding history with GET /v1/funding and per-market rates with GET /v1/fundingRates. Stream live funding payments over the new funding WebSocket channel — snapshot of the 100 most recent payments on subscribe, then one event per (market, account) at each funding time. Positive payment = received, negative = paid.Portfolio history. GET /v1/portfolio returns account equity, PnL, and value-over-time history for charting.Positions REST endpoint. GET /v1/positions returns the current open positions for an account — the REST counterpart to the existing positions WebSocket channel.Cancel-all and set-leverage. POST /v1/cancelAllOrders cancels every open order for an account in one call; POST /v1/setLeverage updates per-market leverage.Account transfer updates. GET /v1/accountTransferUpdates returns deposit/withdrawal history with cursor pagination.User preferences. Persist client-side UI settings server-side via /v1/api-meta/userPreferences.Referral program. Twelve new endpoints under /v1/api/affiliate/* cover the full affiliate lifecycle — create and revoke referral codes, register affiliates, view referees and leaderboard, track commissions and kickbacks, and claim rewards.
Initial testnet release

New features

REST and WebSocket API now live on testnet. Trade, stream market data, and manage accounts against https://api.testnet.arcus.xyz (REST) and wss://api.testnet.arcus.xyz/v1/ws/ (WebSocket). Both APIs are non-custodial — register an Ed25519 API key against your Ethereum address and the server never sees a private key. See the API introduction to get started.Real-time market data channels. Subscribe to live updates over WebSocket:
  • l2Orderbook and l2OrderbookUpdates — full snapshots every ~500 ms, or initial snapshot plus incremental updates (1–100 levels).
  • bbo — best bid and offer at the top of book.
  • trades — live public trade stream.
  • markets — global market metadata with funding rate, oracle and index prices, and 24h volume.
  • oraclePrices — per-market oracle prices from the on-chain Slinky aggregator.
  • candles — OHLCV across 13 timeframes from 1m to 1w, with up to 200-candle snapshots.
Account and order channels. Track your account state and order lifecycle in real time with account, positions, orders, and userFills.Order routing over WebSocket. Place, cancel, modify, and batch orders directly over WebSocket. All order methods are asynchronous and return a 202 ACK — observe lifecycle through the orders and userFills channels. See Placing orders.Ed25519 API keys with Ethereum-signed registration. Generate an Ed25519 key pair, register it with an ECDSA signature from your master Ethereum address, and sign protected requests with a Unix-millisecond timestamp. Full instructions in Authentication.

Updates

Rebranded to Arcus. The product is now Arcus across all user-facing surfaces, including the API spec and documentation.

Known limitations

  • batchModifyOrders is not yet implemented and returns 501.
  • createApiKey is REST-only; the WebSocket equivalent returns 501 NotImplemented.