Skip to main content

v1.0.12 (March 2026)

Breaking Changes

These changes require updates to your integration.

Unified Transaction Envelope (POST /order and WebSocket trading)

All signed requests now use a single envelope. The previous nested action / orders structure is no longer used. Before:
{
  "action": {
    "type": "order",
    "orders": [...],
    "nonce": 1704067200000000000
  },
  "account": "...",
  "signer": "...",
  "signature": "..."
}
After:
{
  "actions": [{"l": {"c": "BTC-USD", "b": true, "px": 100000.0, "sz": 0.1, "tif": "GTC", "r": false}}],
  "nonce": 1704067200000000000,
  "account": "...",
  "signer": "...",
  "signature": "..."
}
Action tags: 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:
bincode_serialize(actions) + nonce_le_u64 + account_pubkey_bytes
Do not include 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 points
  • buy / sell - 2D arrays indexed by [notional_idx][leverage_idx], each cell { mmrO, mmrE, p }
  • corrs - Array of [pair, correlation]
  • regime - Integer -12 to 12
Previous power-law style fields (lambdaBuy, lambdaSell, buyCoefA/B, sellCoefA/B) are no longer used.

POST /account: fullAccount Response Shape

The fullAccount response now returns:
  • margin - Object with totalBalance, availableBalance, marginUsed, notional, realizedPnl, unrealizedPnl, fees, funding
  • positions - Array with full position fields (e.g. fairPrice, notional, liquidationPrice, maintenanceMargin, lambda, riskAllocation, allocMargin)
  • openOrders - Array of order state objects
  • leverageSettings - Array of { symbol, leverage }
Previous 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:
FieldDescription
regimeMarket regime indicator
regimeDtRegime duration (10s intervals)
regimeVolRegime-adjusted volatility
regimeMvRegime mean value
fairBookPxFair price from order book
fairVolFair volatility estimate
fairBiasFair price bias
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 optional reason 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, cancelAllRejected with full payloads. See Account stream.
Legacy 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

Documentation now includes explicit response examples and field descriptions for openOrders and fills query types (array of objects with keys openOrder and fills respectively).

v1.0.11 (January 2026)

Breaking Changes

This is a critical signing update. Existing signing implementations must be updated.

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) as Option<Hash>
  • Faucet user field is now raw 32-byte pubkey (not string)
Action Discriminants:
const ACTION_CODES = {
  order: 0,
  oracle: 1,
  faucet: 2,
  updateUserSettings: 3,
  agentWalletCreation: 4,
};
Order Item Discriminants:
const ORDER_ITEM_CODES = {
  order: 0,
  cancel: 1,
  cancelAll: 2,
};
See Transaction Signing for the complete implementation with binary layout reference.

v1.0.10 (January 2026)

Breaking Changes

These changes require updates to your integration.

Nonce Requirement for Signed Transactions

All signed transactions now require a nonce field (u64) for replay protection. Before:
{
  "action": {
    "type": "order",
    "orders": [...]
  },
  "account": "...",
  "signer": "...",
  "signature": "..."
}
After:
{
  "action": {
    "type": "order",
    "orders": [...],
    "nonce": 1704067200000000000
  },
  "account": "...",
  "signer": "...",
  "signature": "..."
}
Recommendation: Use nanosecond timestamps: BigInt(Date.now()) * 1_000_000n Affected endpoints:
  • POST /order - Place/cancel orders
  • POST /agent-wallet - Manage agent wallets
  • POST /user-settings - Update user settings
  • POST /private/faucet - Request testnet funds

New Features

WebSocket: Subscription Response Format

Subscription confirmations now return topic strings instead of numeric IDs. New Format:
{
  "type": "subscriptionResponse",
  "topics": ["ticker.BTC-USD", "trades.BTC-USD"]
}

WebSocket: Unsubscription via Topic String

{
  "method": "unsubscribe",
  "topic": "ticker.BTC-USD"
}

WebSocket: Batched Account Subscriptions

Subscribe to multiple accounts in a single request:
{
  "method": "subscribe",
  "subscription": [{
    "type": "account",
    "user": ["pubkey1", "pubkey2", "pubkey3"]
  }]
}

WebSocket: Unified orderUpdate Message

All order state changes now use a single orderUpdate message type with comprehensive state information.
{
  "type": "account",
  "data": {
    "type": "orderUpdate",
    "status": "filled",
    "symbol": "BTC-USD",
    "orderId": "...",
    "price": 100000.0,
    "originalSize": 0.1,
    "size": 0.0,
    "filledSize": 0.1,
    "vwap": 100025.5,
    "isBuy": true,
    "maker": false,
    "timestamp": 1763316177219383423,
    "reason": null
  },
  "topic": "account.pubkey"
}

Account Query: New Query Types

Three new query types added to POST /account:
  • positions - Closed position history (last 5000)
  • fundingHistory - Funding payment history (last 5000)
  • orderHistory - Terminal order history (last 5000)
{"type": "positions", "user": "..."}
{"type": "fundingHistory", "user": "..."}
{"type": "orderHistory", "user": "..."}

WebSocket: Frontend Context Stream

New stream for aggregated market data across all symbols:
{
  "method": "subscribe",
  "subscription": [{"type": "frontendContext"}]
}
Returns summary data for all markets every 2 seconds.

WebSocket: Risk Metrics Stream

Subscribe to coin-based risk metrics:
{
  "method": "subscribe",
  "subscription": [{
    "type": "risk",
    "symbol": "BTC-USD"
  }]
}

Improvements

Expanded Order Status Types

Added granular status types for better order tracking:
StatusDescription
placedOrder placed and resting on book
workingPartial fills, still resting
filledFully filled
partiallyFilledPartially filled and terminal
cancelledCancelled by user
cancelledRiskLimitCancelled - risk limit exceeded
cancelledSelfCrossingCancelled - self-trade prevention
cancelledReduceOnlyCancelled - would increase position
cancelledIOCIOC expired without full fill
rejectedCrossingPost-only rejected for crossing
rejectedDuplicateDuplicate order ID
rejectedRiskLimitRejected - risk limit on submission
rejectedInvalidInvalid order parameters

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 size
  • vwap - Volume-weighted average fill price
  • maker - Maker/taker indicator
  • reduceOnly - Reduce-only flag
  • tif - Time in force

Migration Guide

1. Add Nonce to Signed Transactions

const nonce = BigInt(Date.now()) * 1_000_000n;

const action = {
  type: "order",
  orders: [...],
  nonce: nonce  // Required
};
Update your bincode serialization to include nonce.

2. Update WebSocket Subscription Handling

// Old way (deprecated)
ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.channel === 'subscriptionResponse') {
    // Handle numeric IDs
  }
});

// New way
ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.type === 'subscriptionResponse') {
    console.log('Subscribed to:', msg.topics);
  }
});

3. Handle New Order Status Types

switch(orderUpdate.status) {
  case 'placed':
  case 'working':
    // Non-terminal - order is active
    break;
  case 'filled':
  case 'partiallyFilled':
  case 'cancelled':
  case 'cancelledRiskLimit':
  case 'cancelledSelfCrossing':
  case 'cancelledReduceOnly':
  case 'cancelledIOC':
  case 'rejectedCrossing':
  case 'rejectedDuplicate':
  case 'rejectedRiskLimit':
  case 'rejectedInvalid':
    // Terminal - order is complete
    break;
}

Previous Versions

v1.0.0

  • Initial public API release
  • HTTP REST API
  • WebSocket streaming
  • Ed25519 transaction signing