v1.0.20 (4th October 2026)
Scheduled upgrade — Sunday, 4 October 2026. The changes below take effect
after the upgrade; they are not an announcement that deployment has completed.
All maintenance times are UTC.
Maintenance Schedule
Only resting ALO / post-only orders will be cleared. GTC and already-placed
conditional orders remain untouched by the clearing process. Untriggered on-fill
actions attached to a cleared post-only order are removed with that parent order.
After reconnecting, reconcile open orders and refresh account and market-data
snapshots before resuming normal order submission.
Breaking Changes
Market Size Metadata
GET /exchangeInfo replaces sizePrecision
and lotSize with sizeDecimals and sizeIncrement.
Illustrative partial response; read the actual values for each market:
sizeDecimals is the maximum order-size decimal width, capped at eight wire
decimal places. sizeIncrement is the smallest representable quantity step,
not the minimum trade value; minNotional remains a separate requirement.
Account-Local and Aggregate Margin
Public account responses retain themargin object. Unprefixed fields
describe the queried account only. Optional agg* fields report that account
plus its attached isolated accounts, not separate sub-accounts.
Selected fields from a POST /account response:
agg* fields are omitted when no isolated owners are attached.
Positions and open orders remain a combined parent-plus-isolated view, with
isolated rows identified by iso and isoPubkey.
WebSocket account snapshots use the same margin object:
marginUpdate messages; consume account
snapshots for the combined margin view. See
Account Stream for the complete field reference.
Conditional-Order Signing
Update the signing encoder for new conditional orders and batches containing conditional actions. The new optional slippage fields participate in the upgraded signing schema even when an override is omitted. An older conditional encoder is not made compatible merely by leaving those fields out of JSON. Use the updated SDK signing implementation. This requirement concerns new signed submissions; existing conditional orders are preserved through the upgrade. See Transaction Signing.New Features
ALO Slide and ALO Join
ALO_SLIDEmoves a crossing post-only order to the nearest non-crossing display tick.ALO_JOINmoves a crossing post-only order to the best quote on its own side of the book. If no same-side quote exists, it falls back to Slide.
actions array, over
either HTTP or WebSocket:
JSON requests use the names, not the numeric indices. Existing signing indices
remain
GTC = 0, IOC = 1, and ALO = 2. GET /exchangeInfo advertises
uppercase names in timeInForces. Read the reported working price rather than
assuming it equals the submitted price.
See Place & Cancel Orders
and Trading via WebSocket.
Configurable Conditional Slippage
Market-executing stop, take-profit, and trailing orders accept optionalslippage overrides in basis points. Range orders support independent
slSlippage and tpSlippage values for their stop-loss and take-profit legs.
When omitted, the applicable market default is used. Explicit limit-executing
legs retain their limit price. Slippage controls do not guarantee a fill.
Improvements
Resting-Order Price Alignment
Orders capable of resting, including GTC and the ALO family, align to the market’spricePrecision / tickSize: buys round down and sells round up.
IOC orders retain native fixed-point price precision.
Performance and Correctness
- Order-processing performance and efficiency improvements.
- More accurate account, leverage, and isolated-margin reporting.
- Funding and liquidation precision fixes.
- Improved liquidation-related market-data reporting.
v1.0.19 (2nd September 2026)
Improvements
Primary Mainnet Endpoints
New integrations should use the dedicated mainnet endpoints:exchange-api.bulk.trade and exchange-ws1.bulk.trade. Request paths, transaction payloads, subscriptions, and response schemas are unchanged; signed transactions must use the signature domain for the target network.
Atomic L2 Delta Batches
Deployed to Mainnet at 20:00 UTC. Thel2Delta WebSocket stream now publishes all changed price levels for an
instrument update together in one atomic message. Previously, each changed
price level was published as a separate message.
The subscription topic and JSON schema are unchanged. levels remains a
two-element array of [bids, asks], but either side may now contain multiple
changed levels in the same message. Clients should apply the complete message
as one order-book transition before exposing the updated local book.
Clients that are disconnected or fall behind as slow consumers must not
continue applying deltas to a stale book. Reconnect, request a fresh
l2Snapshot, rebuild the local book, and then resume l2Delta processing.
No API-breaking change is expected for clients that already process every
level in both sides of each delta message.
v1.0.18 (21st August 2026)
Breaking Changes
Risk-Surface Response
Risk REST and WebSocket responses now contain:liveRegime, identifying the active risk regime- a
leverageobject withmin,max,margin_0, andmargin_half surfaces[], containing every regime’sregime,leverage[],notionals[],buy[][], andsell[][]- the existing correlation data
regime, leverage[],
notionals[], buy[][], and sell[][] were top-level fields.
New Features
Size-Impact API
GET /impact returns the latest cached size-impact
curve for the requested market. The market query parameter is required.
The response contains:
symbol- millisecond
timestamp minSizesellBpsandbuyBps, each containinglogMin,logRange, and exactly 250 impact values at log-uniform size knots
404 until the first curve is available for that market.
The WebSocket impact subscription accepts a market symbol, publishes on
impact.<symbol>, sends the cached curve immediately when one is available,
and then sends future updates. It sends no initial event before the first curve
is available.
Account Data
- Position snapshots, history rows, and WebSocket position updates may expose
averageEntryTime, the average entry time in nanoseconds. - Full account snapshots may include
lockedAmounts[]while a transfer or withdrawal is in progress. Each lock contains the actionhash,symbol,amount, and nanosecondlockedAttime. Account WebSockets emitlockedAmountsUpdate; an empty array means all locks have cleared.
Improvements
Order-Size Corrections
Order responses now report the current remaining quantity after partial fills:working.remainingSzreports the remaining quantity and is clamped at zerofullAccount.openOrders[].sizeand account WebSocket snapshot ordersizereport signed remaining quantity- regular and conditional WebSocket
orderUpdate.szreport signed remaining quantity
originalSize or origSz,
and filled quantity remains available as filledSz or fillSz.
Upgrade Response
During an upgrade, transaction admission may temporarily return503 with:
Retry-After. Clients should retry with bounded
backoff.
v1.0.17 (31st July 2026)
Breaking Changes
Network-Bound Transaction Signatures
Every signed transaction is now bound to one Bulk network:
For raw Ed25519 signing, append the configured byte to the canonical preimage:
app_domain = signature_domain_u8 || 31 zero bytes- the clear-sign payload includes
Network: <mainnet|testnet|devnet>and hashes the domain-bound canonical preimage
Trigger and OnFill Actions
Trigger baskets no longer carry a top-leveli field or append an isolated-routing
byte to the canonical signing payload. Each nested order or conditional action
still carries its own i.
OnFill now uses one action with an embedded market or limit order:
Paginated Account History
The unsignedPOST /account endpoint now supports bounded pagination for
fills, positions, fundingHistory, orderHistory, activityHistory, and
riskHistory.
limit defaults to 5000 and accepts 1–5000. First-page startSlot and
endSlot bounds are inclusive. Continue with the same type and user, the
opaque cursor, and an optional new limit; do not include slot bounds with a
cursor.
Every history response contains typed rows in data and frozen traversal,
coverage, and retention metadata in page. Rows are ordered newest-first by
slot and server sequence. Use nextCursor for continuation rather than
timestamps or payload fields.
A direct physical-account query reads that account’s history. A parent query
returns the parent’s own rows plus rows assigned to it when an isolated account
event was written. Detaching or reparenting an isolated account does not move
earlier history. See Query Account.
Improvements
Account Fill tradeId
REST account-fill history and account WebSocket fill updates now expose
tradeId as a lossless "<slot>:<event-sequence>" string. Maker, taker, and
isolated-account views of the same execution share the same value.
Treat tradeId as an opaque, network-local reconciliation key. It is not
portable across forks or networks, and sequence gaps in one account’s view are
expected. This field applies to account fill surfaces; it does not add an ID to
the public market-trades stream.
See Query Account
and Account WebSocket Events.
v1.0.16 (10th July 2026)
Client update required.
bulk-client has been bumped to 0.1.2 for builder-code support. Update before exercising the builderCode, abc, and rbc fields below.New Features
Builder Codes (live)
Builder codes are now live on BULK’s exchange endpoints for routed-order-flow attribution. A user first approves a builder-code recipient withabc, routed m/l orders may include builderCode: { "to": "...", "fee": 5 }, and approval can be revoked with rbc.
v1.0.15 (20th May 2026)
Client updates required.
bulk-client and bulk-cli have been bumped to 0.1.1 to enable the changes in this release. Update both before exercising the new endpoints / fields below.New Features
Offchain Signing Mode (any transaction shape)
Transactions can now be signed via the Solana v0 offchain-message envelope in addition to the default raw canonical-binary path. The signed bytes are the full offchain envelope wrapping a deterministic clear-sign text payload (Bulk Exchange Transaction, Account, Nonce, Actions, Signable-Hash, plus per-action lines). format = 0x00 for ASCII payloads and format = 0x01 for UTF-8.
Header is hint only; signature validity still decides accept/reject. See Offchain Signing Mode and Optional Handshake Headers.
The legacy compatibility path for owner-signed
agentWalletCreation (signature over bs58_encode(canonical_binary_message).as_bytes()) is retained for older wallet UIs.
POST /account Query Type: riskHistory
New unsigned query returning the last 5000 liquidation, ADL, and risk-vault events for a master or sub-account. For master/sub queries, results include both base-account rows and per-instrument isolated-account rows (iso = true).
This query now supports bounded pagination through optional
limit, cursor,
startSlot, and endSlot body fields. See Query
Account.
Improvements
feeTier Query Response Simplified (Account-Only)
POST /account with type: "feeTier" now returns just the account fee-tier quote (scopeInstrument, rollingVolume, tierIndex, tierThreshold, makerBps, takerBps, windowDays). Global fee-state fields (globalPolicyActive, scopes, settledFills, totals, etc.) live on GET /feeState.
liquidation_sweep Reason Code
A new 3 = liquidation_sweep value joins the fill reasonCode set (0 = normal, 1 = liquidation, 2 = adl, 3 = liquidation_sweep) and the closed-position closeReason enum. Affected surfaces:
- Trades stream (
reasonlabel) - Account stream fill rows (
reasonCode) POST /accountfills/positionshistory responses
ADL Account-Stream Event: adl (lowercase) + reason
The data.type value on the account stream ADL event changed from "ADL" to
"adl" to match the rest of the stream’s casing convention. The liquidation
and ADL events now also carry an optional human-readable reason field. The
historical POST form introduced in this release now supports bounded
pagination through type: "riskHistory". See Query
Account.
subAccounts[] on Master Snapshots, name on Sub-Account Snapshots
The subAccounts array on a master’s fullAccount snapshot (both HTTP POST /account and the WS account stream) returns rows containing only {pubkey}. To resolve a sub-account’s display name, query/subscribe to that sub-account directly; its snapshot carries a top-level name field when kind: "SubAccount".
marginAmount Must Be JSON Numbers
createSubAccount.marginAmount and transfer.marginAmount must be unquoted JSON numbers (e.g. 100.0, not "100.0"). Strings are rejected.
v1.0.14 (28th April 2026)
New Features
Sub-Accounts (createSubAccount, removeSubAccount, renameSubAccount)
Master accounts can now create, rename, and remove sub-accounts via the unified POST /order endpoint. Sub-accounts are off-curve, protocol-derived accounts under a master with their own margin, positions, and risk profile.
See Sub-Accounts API.
Native Margin Transfers (transfer)
Move margin between accounts directly inside the protocol, with no external bridge or wrapper.
External transfers to off-curve addresses that are not protocol accounts are rejected; no implicit account creation.
See Transfer API.
Isolated Account Routing (i flag on l, m, st, tp, rng, trig, trl)
Order actions that produce a position now carry a required i boolean. Setting i = true routes the order into a per-instrument isolated account (IsoAccount) auto-derived from the signing account and the instrument. Isolated-account positions and history rows are flagged with iso = true and expose an isoPubkey for direct margin top-up via transfer. Isolated accounts are torn down via removeSubAccount against the isolated-account pubkey.
See Isolated Margin and Place & Cancel Orders.
Trading From a Sub-Account
Every signed action (orders, modify, cancel, conditional baskets, on-fill, transfers, user settings) now works on a sub-account by setting the transactionaccount field to the sub-account pubkey while the master, the sub-account itself, or an agent wallet registered on either signs. There is no separate sub-account endpoint or action variant. Agents registered on a master are automatically authorized for that master’s sub-accounts; sub-accounts can additionally register their own agents independently.
See Sub-Accounts: Trading From a Sub-Account.
Improvements
fullAccount Top-Level Fields
The full-account snapshot now exposes account hierarchy and authorization state:
See Query Account.
iso Flag on Account Rows
Positions, open orders, fills, closed positions, funding payments, and order history rows all carry an iso boolean. When iso=true, position rows additionally expose isoPubkey, the per-instrument isolated account’s pubkey. Master/sub POST /account history queries return both base-account and per-instrument isolated-account rows. In v1.0.17, isoPubkey also became valid as user with the paginated history types for direct physical history across that pubkey’s account lifecycle. It remains invalid with current-state query types and as transaction account.
New Response Status Types
POST /order now emits dedicated status rows for the new actions:
See Place & Cancel Orders for the full status table.
v1.0.13 (16th April 2026)
New Features
Conditional Order Types (st, tp, rng, trig, trl, of)
Six conditional order types are now fully documented with request/response examples across HTTP and WebSocket:
See Place & Cancel Orders and Trading via WebSocket for full examples.
Conditional Response Statuses
New status types for conditional order lifecycle:Breaking Changes
Signed Sizes in Order Responses
Size fields in order responses are now signed: negative values indicate sell-side intent. Affected fields:totalSzinfilled/partiallyFilledstatusesfilledSz/remainingSzinworkingstatusfilledSzincancelledIocstatusorigSz/szin WebSocketorderUpdatemessages
totalSz of -0.1 means 0.1 BTC was sold. Previously all sizes were positive with direction inferred from isBuy.
WebSocket orderUpdate Compact Format
The orderUpdate message uses compact field names and includes trigger metadata for conditional orders:
New fields:
ot (order type), mk (maker flag), trigger (trigger metadata object with isAbove, px, lim, oco, pxHi, limHi, trb, stb), pendingOnFill.
See Account Stream for the full orderUpdate reference.
v1.0.12 (March 2026)
Breaking Changes
Unified Transaction Envelope (POST /order and WebSocket trading)
All signed requests now use a single envelope. The previous nestedaction / orders structure is no longer used.
Before:
l (limit), m (market), mod (modify), cx (cancel one), cxa (cancel all). Other actions (faucet, updateUserSettings, agentWalletCreation) use the same envelope.
Affected: POST /order, WebSocket post requests for trading.
Signed Message Format (signer excluded)
The bytes that get signed no longer include the signer public key. Message to sign:signer or signature in the signed message. signer remains in the JSON payload for authorization.
See Transaction Signing for the full specification.
WebSocket: Ping-Pong Keepalive Required
The server sends a WebSocket ping frame every 30 seconds. The client must reply with a pong frame. If no pong is received within 10 seconds, the server closes the connection. Ping and pong are transport-level WebSocket frames, not JSON application messages. Clients that do not respond to ping will be disconnected.WebSocket: Risk Metrics Stream Structure
The risk stream payload has changed to the asset risk format. New structure:leverage- Knot list (e.g. 1.0 … 50.0)notionals- Notional knot pointsbuy/sell- 2D arrays indexed by[notional_idx][leverage_idx], each cell{ mmrO, mmrE, p }corrs- Array of[pair, correlation]regime- Integer -12 to 12
lambdaBuy, lambdaSell, buyCoefA/B, sellCoefA/B) are no longer used.
POST /account: fullAccount Response Shape
ThefullAccount response now returns:
margin- Object withtotalBalance,availableBalance,marginUsed,notional,realizedPnl,unrealizedPnl,fees,fundingpositions- Array with full position fields (e.g.fairPrice,notional,liquidationPrice,maintenanceMargin,lambda,riskAllocation,allocMargin)openOrders- Array of order state objectsleverageSettings- Array of{ symbol, leverage }
marginSummary / settings.maxLeverage shape is no longer used. Response body is an array of single-key objects (e.g. [{ "fullAccount": { ... } }]).
New Features
GET /stats (Market Data)
New endpoint for exchange statistics. Endpoint:GET /stats
Query parameters: period (1d, 7d, 30d, 90d, 1y, all), symbol (optional filter)
Returns aggregate volume, open interest, funding rates, and per-market stats. See Get Exchange Statistics.
Deterministic Order IDs
Order IDs are derived from the transaction (action, account, nonce, action index). No client order ID is required. You can compute the order ID before or after sending; use bulk-keychain (Node, browser, Python, Rust) to compute them. See Order IDs.WebSocket Ticker: Regime and Fair Price Fields
Ticker stream now includes:
Timestamp is in nanoseconds.
WebSocket Candles: Additional Intervals
Candle stream supports additional intervals:3m, 30m, 2h, 6h, 8h, 12h, 3d, 1w, 1M.
WebSocket Trades: reason Field
Trade messages may include optionalreason when not a normal trade: e.g. "liquidation", "adl".
WebSocket Account Stream: allocMargin and New Events
- Position field:
allocMargin(allocated margin for the position) added to snapshot and position updates. - New event types:
liquidation,ADL,cancelOneRejected,cancelAllRejectedwith full payloads. See Account stream.
order messages with status: "placed" or "cancelled" may still be sent; new integrations should use orderUpdate only.
WebSocket Trading: deposit and agentWallet Status Types
Response status types for faucet and agent-wallet flows:deposit, agentWallet.
Official Signing Library: bulk-keychain
bulk-keychain is the official signing library for Node.js, browser (WASM), Python, and Rust. It produces the correct canonical encoding and supports order ID computation. See Transaction Signing and Order IDs.Improvements
Wincode and Bincode Compatibility
On the wire, wincode and bincode are the same (bincode-compatible encoding). See wincode for the Rust crate.POST /account: Open Orders and Fills Response Examples
At the time, documentation added response examples and field descriptions for theopenOrders and fills query types. fills now returns a paginated
{data, page} object; openOrders retains its existing array shape.
v1.0.11 (January 2026)
Breaking Changes
Signing Implementation Update (wincode format)
The transaction signing has been updated with the correct wincode serialization format: Key Changes:- Action types now use u32 enum discriminants (not length-prefixed strings)
- Order items (
order,cancel,cancelAll) use u32 discriminants - Pubkeys and Hashes are serialized as raw 32 bytes (decoded from base58)
- Added support for
cloid(client order ID) asOption<Hash> - Faucet user field is now raw 32-byte pubkey (not string)
v1.0.10 (January 2026)
Breaking Changes
Nonce Requirement for Signed Transactions
All signed transactions now require anonce field (u64) for replay protection.
Before:
BigInt(Date.now()) * 1_000_000n
Affected endpoints:
POST /order- Place/cancel ordersPOST /agent-wallet- Manage agent walletsPOST /user-settings- Update user settingsPOST /private/faucet- Request testnet funds
New Features
WebSocket: Subscription Response Format
Subscription confirmations now return topic strings instead of numeric IDs. New Format:WebSocket: Unsubscription via Topic String
WebSocket: Batched Account Subscriptions
Subscribe to multiple accounts in a single request:WebSocket: Unified orderUpdate Message
All order state changes now use a single orderUpdate message type with comprehensive state information.
Account Query: New Query Types
Three history query types were added toPOST /account in this release. They
now accept optional pagination and inclusive slot-bound body fields:
positions- Closed position history (last 5000)fundingHistory- Funding payment history (last 5000)orderHistory- Terminal order history (last 5000)
WebSocket: Frontend Context Stream
New stream for aggregated market data across all symbols:WebSocket: Risk Metrics Stream
Subscribe to coin-based risk metrics:Improvements
Expanded Order Status Types
Added granular status types for better order tracking:L2 Delta Stream Behavior
L2 Delta provides an initial snapshot (latest cached book state) on subscription, followed by real-time delta updates for every price level change.Enhanced Account Snapshot
Account snapshot now includes additional fields:originalSize- Original order sizevwap- Volume-weighted average fill pricemaker- Maker/taker indicatorreduceOnly- Reduce-only flagtif- Time in force
Migration Guide
1. Add Nonce to Signed Transactions
2. Update WebSocket Subscription Handling
3. Handle New Order Status Types
Previous Versions
v1.0.0
- Initial public API release
- HTTP REST API
- WebSocket streaming
- Ed25519 transaction signing