API Changelog
Kyan API Changelog
All notable changes to the Kyan API will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.16.0] - 2026-02-13
Added
-
New endpoint:
POST /heartbeatfor automatic order cancellation (dead man's switch)Automated trading systems can now send periodic heartbeat pings. If no heartbeat is received within the configured timeout, all open orders for the maker are automatically cancelled.
Request example:
// With EIP-712 signature const response = await fetch('/heartbeat', { method: 'POST', headers: { 'x-apikey': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ maker: '0xYourAddress', timeout: 60, // Cancel all orders if no ping within 60 seconds signature: '0x...', signature_deadline: Math.floor(Date.now() / 1000) + 30 }) }); // With one-click session (no signature needed) const response = await fetch('/heartbeat', { method: 'POST', headers: { 'x-apikey': API_KEY, 'x-one-click': SESSION_HASH, 'Content-Type': 'application/json' }, body: JSON.stringify({ maker: '0xYourAddress', timeout: 60 }) });Replay protection: When using signatures,
signature_deadlinemust be strictly greater than the last accepted deadline for the maker (deadline monotonicity). Deadlines are bounded to 30 seconds in the future.Benefits: Prevents stale orders from sitting on the book when trading bots crash or lose connectivity.
-
New EIP-712 signature type:
HeartbeatType8th signature type added for signing heartbeat pings:
const HeartbeatType = [ { name: 'deadline', type: 'uint256' }, { name: 'maker', type: 'address' }, { name: 'timeout', type: 'uint256' }, ]; -
WebSocket server message envelope fields:
message_idandseq_idAll server messages now include two new fields for reliability:
message_id(string): UUID v4 unique to each message — use for deduplicationseq_id(number): Monotonically increasing per connection, starting at 1 — use for gap detection
{ "kind": "event", "type": "trade", "timestamp_ms": 1677721600000, "message_id": "550e8400-e29b-41d4-a716-446655440000", "seq_id": 42, "data": { ... } }Benefits: Enables reliable message processing — detect missed messages via
seq_idgaps and avoid processing duplicates viamessage_id. -
New WebSocket message type:
resendfor message recoveryWhen a gap in
seq_idis detected, request the server to re-deliver missed messages:{ "type": "resend", "begin_seq_id": 10, "end_seq_id": 15 }- Maximum range: 100 messages per request
- Messages are cached per connection with limited capacity (LRU eviction) and TTL
- Resent messages retain their original
seq_idandmessage_id - Rate limited: 5 requests per 10 seconds
Benefits: Enables reliable, lossless event processing without requiring full resubscription after brief network hiccups.
-
New error codes for enhanced validation feedback
Three new error codes added to
StandardError:SIGNATURE_DEADLINE_STALE— Signature deadline is not strictly greater than the last accepted deadline (replay protection)ONE_CT_USER_MISMATCH— One-click trading session was created by a different address than the maker/taker in the requestVALUE_INVALID— A request field has an invalid value (e.g., heartbeat timeout out of range)
Changed
-
Breaking Change: Market and combo trade responses simplified
The
unprocessedOrdersandrejectedOrdersfields have been removed fromPOST /marketandPOST /comboresponses.Before:
{ "fillResult": { ... }, "filledOrders": [...], "rejectedOrders": [...], "unprocessedOrders": [...] }After:
{ "fillResult": { ... }, "filledOrders": [...] }Migration: Remove references to
rejectedOrdersandunprocessedOrdersfrom response handling code. All successfully processed orders appear infilledOrders.Benefits: Cleaner response structure — these fields were vestigial and always empty in practice.
-
PATCH /limitnow triggers IOC matching for non-post-only orders crossing the marketWhen editing a non-post-only order to a price that crosses the market (e.g., buy price above best ask), the order triggers immediate matching against resting orders (IOC-style). The order's
filled_amountresets to 0 and the new size is used for matching.Before: Edited orders that crossed the market were rejected.
After: Non-post-only edited orders that cross the market are immediately matched. Post-only orders crossing the market are still rejected with
post only violation.Benefits: More flexible order editing for aggressive traders — modify orders without needing to cancel and re-submit.
-
Price and size increment validation now applies to liquidation orders
Liquidation orders are no longer exempt from price and size increment constraints. All orders (including
liquidation: true) must comply with the same increment rules returned byGET /api/v1/exchange_info.Benefits: Consistent validation across all order types ensures orderbook integrity.
-
Account history endpoint sorting enhanced
The
sortparameter has been replaced with two parameters:sortKey: Field to sort by —timestamp(default) orrealized_pnlsortOrder: Direction —desc(default) orasc
Response now includes
total_countandtotal_pageswhen available.Before:
GET /account_history?address=0x...&sort=descAfter:
GET /account_history?address=0x...&sortKey=timestamp&sortOrder=desc GET /account_history?address=0x...&sortKey=realized_pnl&sortOrder=ascMigration: Replace
sortparameter withsortKey+sortOrder.Benefits: Sort by realized P&L for performance analysis; total counts enable proper pagination UI.
-
POST /calculate_user_riskresponse:future_settlement_projectionsnow requiredThe
future_settlement_projectionsfield is now always present in the response (previously optional). -
WebSocket rate limit corrections
Message Type Rate Limit Window (corrected) subscribe10 requests 1 second (was documented as 10 seconds) unsubscribe10 requests 1 second (was documented as 10 seconds) unsubscribe_all1 request 1 second (was 10 req/10s)
Documentation
- Added
POST /heartbeatendpoint to OpenAPI specification - Added
HeartbeatTypeas 8th EIP-712 signature type to signatures guide - Added
resendmessage type with full request/response examples to WebSocket documentation - Added server message envelope fields (
message_id,seq_id) section to WebSocket documentation - Added gap detection example code to WebSocket documentation
- Updated rate limit table with
resendentry and corrected windows - Clarified WebSocket heartbeat note: "no WebSocket-level ping/pong" vs REST heartbeat endpoint
[1.15.0] - 2026-01-31
Added
-
New WebSocket channel:
positionfor real-time position updatesSubscribe to receive position updates every second for your margin accounts with enriched market data including mark prices and Greeks.
Subscription example:
{ "type": "subscribe", "subscriptions": [ { "channel": "position", "query": { "account": "0x1234567890abcdef1234567890abcdef12345678", "market": "ETH" } } ] }Query parameters:
account(required): Smart account addressmarket(optional): Base token filter (BTC, ETH, ARB)
Event payload:
{ "kind": "event", "type": "position", "timestamp_ms": 1705420800000, "data": { "margin_account": "550e8400-e29b-41d4-a716-446655440000", "market": "ETH", "positions": [ { "instrument_name": "ETH_USDC-PERPETUAL", "size": 10.5, "average_price": 2450.00, "instrument_type": "perp", "mark_price": 2475.00, "current_funding_rate": 0.0001, "position_greeks": { "delta": 10.5 } } ] } }Benefits: Dedicated position channel provides 1-second updates with enriched market data, separate from account state events.
-
Account History V2 endpoint with cursor-based pagination
Enhanced account history endpoint at
/v2/account_historywith standardized event structures, advanced filtering, and efficient cursor-based pagination.New features:
- Cursor-based pagination via
cursorandnext_cursorfields - Sort order control (
sort: asc/desc) - Event type filtering (
event_types: trade, transfer, settlement, funding) - Action filtering (
actions: buy, sell, deposit, withdrawal) - Transfer type filtering (
transfer_type: internal, external) - Market/instrument filtering (
markets: BTC, ETH, ARB)
Request example:
const params = new URLSearchParams({ address: '0x1234...', event_types: 'trade,transfer', sort: 'desc', limit: '50', }); const response = await fetch(`/v2/account_history?${params}`); const data = await response.json(); // Paginate with cursor if (data.has_more) { const nextPage = await fetch(data.next_cursor_url); }Response structure:
{ "address": "0x1234...", "limit": 50, "returned": 50, "has_more": true, "next_cursor": "eyJ0aW1lc3RhbXAi...", "next_cursor_url": "https://api.kyan.sh/v2/account_history?...", "events": [ { "id": "evt_001", "timestamp": 1705420800, "event_type": "trade", "margin_account_id": "...", "data": { /* event-specific data */ } } ] }Benefits: Efficient retrieval of large datasets, consistent event structures, and flexible filtering reduce client-side processing.
- Cursor-based pagination via
Changed
-
Breaking Change:
account_stateevent no longer includespositionsarrayThe
account_stateWebSocket event payload has been streamlined to remove thepositionsfield.Before:
{ "type": "account_state", "data": { "margin_account": 12345, "pair": "BTC_USDC", "im": 5000.0, "mm": 2500.0, "equity": 15000.0, "portfolio_greeks": { "delta": 0.45, "gamma": 0.0012, ... }, "positions": [{ "instrument_name": "...", "size": 1.5, ... }] } }After:
{ "type": "account_state", "data": { "margin_account": 12345, "pair": "BTC_USDC", "im": 5000.0, "mm": 2500.0, "equity": 15000.0, "portfolio_greeks": { "delta": 0.45, "gamma": 0.0012, ... }, "liquidation": false } }Migration: Subscribe to the new
positionchannel for real-time position data with enriched market information.Benefits: Reduced payload size and bandwidth; position data now available via dedicated channel with 1-second updates.
-
Breaking Change: Order events now use batched array format
WebSocket order events (
post_order,cancel_order,update_order,edit_order) now deliver orders in arrays, allowing multiple orders per message.Before:
{ "type": "post_order", "data": { "order_id": "abc123", "instrument_name": "BTC_USDC-PERPETUAL", "amount": 1000, "price": 98500 } }After:
{ "type": "post_order", "data": [ { "order_id": "abc123", "instrument_name": "BTC_USDC-PERPETUAL", "amount": 1000, "price": 98500 } ] }Migration:
// Before if (event.type === 'post_order') { processOrder(event.data); } // After if (event.type === 'post_order') { for (const order of event.data) { processOrder(order); } }Benefits: Efficient batch delivery reduces message overhead for high-frequency order updates. Single-order events are delivered as single-element arrays for consistency.
-
New
edit_orderWebSocket event typeWhen orders are edited via
PATCH /limit, anedit_orderevent is now emitted on orderbook channels (orderbook_options,orderbook_perps,orderbook_maker).Event payload:
{ "type": "edit_order", "data": [ { "order_id": "abc123", "instrument_name": "BTC_USDC-PERPETUAL", "price": 99000, "amount": 1500, "order_state": "open", "filled_amount": 0 } ] }Note: The edited order retains its original
order_id. Use this event to update local orderbook caches when order prices or sizes change.
[1.14.0] - 2026-01-07
Added
-
Price increment validation for order prices
Order prices must now be divisible by the minimum price increment for the base asset. This ensures consistent pricing across all trading pairs and improves orderbook efficiency.
Price increments by asset:
Asset Minimum Increment BTC $1.00 ETH $0.10 ARB $0.01 Affected endpoints:
POST /limit- validatespricefieldPATCH /limit- validatespricefieldPOST /market- validateslimit_pricefieldPOST /combo- validateslimit_perp_pricefield (perp leg only; option legs are exempt)
New error code:
MIN_INCREMENT_PRICE_VIOLATIONOrders with non-compliant prices will be rejected with HTTP 400:
{ "error": "MIN_INCREMENT_PRICE_VIOLATION", "message": "Min price increment requirement violated for ETH_USDC-PERPETUAL. Price: 2500.15, Must be divisible by: 0.1" }Migration:
// Before (may fail validation) const order = { instrument_name: 'ETH_USDC-PERPETUAL', price: 2500.15, // Not divisible by 0.1 amount: 1000 }; // After (compliant) const order = { instrument_name: 'ETH_USDC-PERPETUAL', price: 2500.10, // Divisible by 0.1 amount: 1000 };Benefits: Consistent pricing grid improves orderbook depth aggregation and reduces price fragmentation.
-
Size increment constraints now documented
Order sizes must be divisible by the size increment for the asset. This validation was already enforced but is now explicitly documented with programmatic access via
/api/v1/exchange_info.Size increments:
Instrument Asset Size Increment Options BTC 0.01 contracts Options ETH 0.1 contracts Options ARB 100 contracts Perpetuals All $1 USD Error code:
MIN_INCREMENT_SIZE_VIOLATION{ "error": "MIN_INCREMENT_SIZE_VIOLATION", "message": "Min size increment requirement violated for BTC_USDC-PERPETUAL. Size: 1.5, Must be divisible by: 1" } -
GET /api/v1/exchange_infoendpoint now documentedThis public endpoint (no authentication required) returns static exchange configuration including:
- Trading pairs and their status
- Order constraints (price increments, minimum sizes, max slippage)
- Instrument specifications and naming formats
- Fee structures
- Rate limits
- WebSocket channel definitions
Usage:
const response = await fetch('https://sandbox.kyan.sh/api/v1/exchange_info'); const config = await response.json(); // Access price increments const btcIncrement = config.orderConstraints.priceIncrements.constraints.BTC; // 1 const ethIncrement = config.orderConstraints.priceIncrements.constraints.ETH; // 0.1 const arbIncrement = config.orderConstraints.priceIncrements.constraints.ARB; // 0.01Benefits: Programmatic access to exchange configuration enables dynamic validation and reduces hardcoded values in client applications.
[1.13.0] - 2025-12-16
Added
-
New endpoint:
PATCH /limitfor editing existing limit orders- Purpose: Modify price and size of existing orders without canceling and resubmitting
- Benefits: Atomic updates preserve queue position for unchanged price, reduced latency for order modifications
- Authentication: Requires EIP-712 signature (one-click sessions not supported)
Request example (options):
const editRequest = { order_id: "abc123def456...", price: 2600.0, // New price contracts: 2.0, // New size for options signature: "0x...", signature_deadline: 1735689600 }; const response = await fetch('/limit', { method: 'PATCH', headers: { 'x-apikey': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(editRequest) });Request example (perpetuals):
const editRequest = { order_id: "abc123def456...", price: 98500.0, // New price amount: 15000, // New size for perpetuals signature: "0x...", signature_deadline: 1735689600 };Constraints:
- Order must exist and belong to the signing maker
- Cannot edit orders during active MMP freeze
- Must edit within the same market as original order
- Size must meet minimum increment requirements
Response: Returns the updated
StoredLimitOrderwith new values andedit_orderevent emitted on WebSocket
Changed
-
Correction: WebSocket trade events do not include order metadata
Trade events contain execution data only. The following fields are not present on trade events:
user_id- Use order events for user trackingorder_size- Use order events for original order sizefilled_amount- Use order events for cumulative fill tracking
Trade event structure (actual):
{ "kind": "event", "type": "trade", "timestamp_ms": 1734355200000, "data": { "margin_account_id": "550e8400-e29b-41d4-a716-446655440000", "smart_account_address": "0x1234567890abcdef1234567890abcdef12345678", "trade_id": "1234567890abcdef1234567890abcdef", "order_id": "abcdef1234567890abcdef1234567890", "size": 1.5, "timestamp": 1734355200000, "direction": "buy", "index_price": 45000.5, "instrument_name": "BTC_USDC-31DEC25-100000-C", "average_price": 2500.0, "limit_price": 2500.0, "liquidation": false, "iv": 0.65, "taker_fee": 0.50, "maker_fee": 0.25, "systemic_risk_fee": 0.10, "liquidation_fee": 0.0, "realised_funding": 0.0 } }Migration: For order lifecycle metadata including
user_id, total order size, and cumulativefilled_amount, subscribe to order events (post_order,update_order,cancel_order) via orderbook channels. -
WebSocket order events now include
user_idfieldOrder events (
post_order,cancel_order,update_order,edit_order) include theuser_idfield when provided during order submission:{ "kind": "event", "type": "post_order", "data": { "instrument_name": "BTC_USDC-31DEC25-100000-C", "order_id": "abc123...", "user_id": "trader_001", "maker": "0x1234...", ... } }Benefits: Track orders across their full lifecycle using your custom identifiers
Fixed
- POST /limit error messages now match backend validation exactly:
- Added: "order size not divisible by minimum increment"
- Fixed: "multiple markets provided" message formatting
- PATCH /limit error messages aligned with
ORDERBOOK_API_ERROR_MESSAGESconstants
[1.12.0] - 2025-11-27
Added
-
New
update_orderWebSocket event for tracking order fill progress- Purpose: Receive real-time notifications when orders are partially or completely filled, enabling precise order state tracking without polling
- Benefits: Instant visibility into order execution, reduced API calls, accurate fill tracking for IOC orders
- New capabilities: Track partial fills, monitor order state transitions, synchronize local order state with exchange
When emitted:
- After a partial fill (order remains
openwith updatedfilled_amount) - After a complete fill (order state changes to
filled) - When IOC (Immediate-or-Cancel) orders are partially filled and reinstated
Event data structure:
{ "kind": "event", "type": "update_order", "timestamp_ms": 1732713600000, "data": { "instrument_name": "BTC_USDC-31DEC25-100000-C", "type": "good_til_cancelled", "contracts": 10.0, "direction": "buy", "price": 2500.0, "post_only": false, "mmp": false, "liquidation": false, "maker": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0", "taker": "0x0000000000000000000000000000000000000000", "order_id": "abc123def456...", "user_id": "user_123", "order_state": "open", "filled_amount": 3.5, "creation_timestamp": 1732713500000, "chain_id": 421614, "deadline": 1732800000, "signature": "0x..." }, "subscription": { "channel": "orderbook", "query": { "instrument_name": "BTC_USDC-31DEC25-100000-C" } } }Key features:
- Complete order state: Event contains the full order object with all fields, not just changes
- No delta processing: Use the
filled_amountandorder_statedirectly without calculating deltas - Book building compatible: The complete order state allows maintaining accurate orderbook representation
Use cases:
- Trading applications tracking order execution progress
- Market makers monitoring fill rates
- Order management systems maintaining accurate order state
- Analytics systems tracking order lifecycle events
Changed
-
Rate limiting now enforced per API key owner instead of per session
Before:
// Old behavior: Each WebSocket connection had independent rate limits const ws1 = new WebSocket('wss://api.premia.io'); // Separate rate limit const ws2 = new WebSocket('wss://api.premia.io'); // Separate rate limit // Each connection could send full quota of requestsAfter:
// New behavior: All connections using same API key share rate limits const ws1 = new WebSocket('wss://api.premia.io'); // Shared rate limit pool const ws2 = new WebSocket('wss://api.premia.io'); // Shared rate limit pool // Total requests across all connections must stay within limitsBenefits:
- Fair resource allocation: Prevents rate limit circumvention via multiple connections
- Better system stability: More predictable load patterns
- Account-level control: Rate limits align with API key ownership
Rate limit details:
Message Type Rate Limit Window Scope auth1 request 1 second Per client IP address get_instruments1 request 1 second Per API key owner get_ob_state_by_instruments5 requests 20 seconds Per API key owner Rate limit exceeded response:
{ "kind": "response", "id": "req-123", "type": "rate_limit_exceeded", "data": { "message": "Rate limit exceeded. Please try again later.", "retry_after_seconds": 15 } }Migration:
- Review applications with multiple WebSocket connections using the same API key
- Implement request coordination across connections to share rate limit quota
- Consider consolidating multiple connections if possible
- Handle
rate_limit_exceededresponses with exponential backoff usingretry_after_seconds - Monitor rate limit errors to optimize request patterns
-
Breaking Change: Orderbook bids/asks arrays now include order_id as third element
Before:
// Old format: [price, amount] const orderbook = await fetch('/order_book?instrument_name=BTC_USDC-PERPETUAL'); const data = await orderbook.json(); // Process bids/asks data.bids.forEach(([price, amount]) => { console.log(`Bid: ${amount} @ ${price}`); // No way to identify specific orders });After:
// New format: [price, amount, order_id] const orderbook = await fetch('/order_book?instrument_name=BTC_USDC-PERPETUAL'); const data = await orderbook.json(); // Process bids/asks with order tracking data.bids.forEach(([price, amount, orderId]) => { console.log(`Bid: ${amount} @ ${price} (Order: ${orderId})`); // Can now track specific orders and match with update_order events });Example REST response:
{ "timestamp": 1732713600, "instrument_name": "BTC_USDC-PERPETUAL", "index_price": 98500.00, "bids": [ [98450.00, 2.5, "order_abc123"], [98400.00, 1.8, "order_def456"], [98350.00, 3.2, "order_ghi789"] ], "asks": [ [98550.00, 1.9, "order_jkl012"], [98600.00, 2.1, "order_mno345"], [98650.00, 1.5, "order_pqr678"] ], "best_bid_price": 98450.00, "best_ask_price": 98550.00 }Example WebSocket snapshot:
{ "kind": "snapshot", "type": "orderbook", "timestamp_ms": 1732713600000, "data": { "bids": [ [98450.00, 2.5, "order_abc123"], [98400.00, 1.8, "order_def456"] ], "asks": [ [98550.00, 1.9, "order_jkl012"], [98600.00, 2.1, "order_mno345"] ] }, "subscription": { "channel": "orderbook", "query": { "instrument_name": "BTC_USDC-PERPETUAL" } } }Benefits:
- Order tracking: Match orderbook levels with specific limit orders
- Event correlation: Connect
update_orderevents with orderbook state - Enhanced analytics: Track order lifecycle from placement to fill
- Better debugging: Identify specific orders causing issues
Migration:
- Update array destructuring to include third element:
[price, amount, orderId] - Update TypeScript types:
Array<[number, number, string]> - Utilize
order_idto correlate withupdate_orderandpost_orderevents - Update any hardcoded array length checks from 2 to 3
- Test orderbook rendering with new three-element format
-
Enhanced
skip_snapshotquery parameter behavior for orderbook subscriptionsBefore:
// Old behavior: skip_snapshot only prevented initial snapshot { "type": "subscribe", "subscriptions": [{ "channel": "orderbook", "query": { "instrument_name": "BTC_USDC-PERPETUAL", "skip_snapshot": true // Skip initial snapshot only } }] } // Would still receive snapshot if re-subscribing to same instrumentAfter:
// New behavior: skip_snapshot prevents duplicate snapshots { "type": "subscribe", "subscriptions": [{ "channel": "orderbook", "query": { "instrument_name": "BTC_USDC-PERPETUAL", "skip_snapshot": true // Skip snapshot for duplicate subscriptions } }] } // Server detects duplicate subscriptions and skips redundant snapshots // Still receive post_order, cancel_order, and update_order eventsBenefits:
- Reduced bandwidth: Eliminates redundant snapshot data for duplicate subscriptions
- Faster reconnection: Re-subscribe without downloading full orderbook again
- Efficient multi-instrument: Subscribe to multiple instruments without snapshot overhead
Use cases:
- Connection recovery: Re-subscribe after brief disconnect without re-downloading full orderbook
- Dynamic subscriptions: Add/remove instruments while maintaining existing subscriptions
- Bandwidth optimization: Minimize data transfer for high-frequency subscription updates
Migration:
- No changes required for existing implementations
- Consider using
skip_snapshot: truewhen re-subscribing to reduce bandwidth - Ensure application can handle orderbook updates without initial snapshot state
Documentation
-
Complete WebSocket API documentation updates
- Added
update_orderevent to Event Types table - Added comprehensive
update_orderevent documentation section with examples - Updated rate limiting section with new per-owner enforcement and complete rate limit table
- Updated rate limit response format to match current JSON structure
- Updated orderbook array format examples throughout documentation
- Added "Orderbook Array Format" explanation section
- Enhanced
skip_snapshotparameter description with duplicate detection behavior
- Added
-
Complete REST API documentation updates
- Updated
/order_bookendpoint OpenAPI schema for 3-element bids/asks arrays - Modified
Orderbook.yamlschema to includeorder_idas third element - Updated array type definitions to
[number, number, string]format - Added descriptive comments explaining the three-element tuple structure
- Updated
[1.11.0] - 2025-10-21
Added
-
New
instrumentsWebSocket channel for real-time instrument list updates- Purpose: Receive immediate notifications when trading instruments are added or expire, keeping your application synchronized with available markets
- Benefits: Eliminates need for polling
/instrumentsendpoint, instant awareness of new trading opportunities, automatic cleanup of expired instruments - New capabilities: Subscribe to specific markets (BTC, ETH, ARB) or all markets, receive initial snapshot on subscription, get update timestamp with each event
Example subscription (single market):
{ "type": "subscribe", "subscriptions": [ { "channel": "instruments", "query": { "market": "BTC" } } ] }Example subscription (all markets):
{ "type": "subscribe", "subscriptions": [ { "channel": "instruments", "query": {} } ] }Event data received:
{ "kind": "event", "type": "instruments", "timestamp_ms": 1677721600000, "data": { "updated_at": 1677721600000, "instruments": [ "BTC_USDC-PERPETUAL", "BTC_USDC-31OCT25-130000-C", "BTC_USDC-31OCT25-130000-P", "BTC_USDC-31OCT25-135000-C", "BTC_USDC-31OCT25-135000-P" ] }, "subscription": { "channel": "instruments", "query": { "market": "BTC" } } }Data fields:
updated_at: Unix timestamp in millisecondsinstruments: Array of instrument names currently available for trading
Query parameters:
market(optional): Base token (BTC, ETH, or ARB). If omitted, subscribes to all markets
Use cases:
- Trading applications dynamically updating available instruments
- Automated trading systems detecting new option expirations
- Market monitoring tools tracking instrument lifecycle
- Risk management systems responding to expired instruments
Changed
-
Breaking Change: Endpoint
GET /instrumentsnow returns object with timestamp instead of arrayBefore:
// Old response format const response = await fetch('/instruments?market=BTC'); const instruments: string[] = await response.json(); // Returns: ["BTC_USDC-PERPETUAL", "BTC_USDC-31OCT25-130000-C", ...]After:
// New response format const response = await fetch('/instruments?market=BTC'); const data: { updated_at: number; // Unix timestamp in milliseconds instruments: string[]; } = await response.json(); // Returns: { // updated_at: 1677721600000, // instruments: ["BTC_USDC-PERPETUAL", "BTC_USDC-31OCT25-130000-C", ...] // } // Access instruments array const instruments = data.instruments; // Use timestamp for caching/change detection const lastUpdate = new Date(data.updated_at); // Convert to Date objectBenefits:
- Cache optimization: Use
updated_attimestamp (milliseconds) to implement efficient caching strategies - Change detection: Compare timestamps to determine if instrument list has changed
- Synchronization: Coordinate REST API data with WebSocket
instrumentschannel updates using the same timestamp - Better performance: Avoid unnecessary processing when instrument list hasn't changed
Migration:
- Update response type to expect object instead of array
- Access instruments via
data.instrumentsproperty - Optionally implement caching using
data.updated_attimestamp - Consider migrating to WebSocket
instrumentschannel for real-time updates
- Cache optimization: Use
-
Breaking Change: Endpoint
POST /limitresponse format simplified -matchedfield removedBefore:
// Old response format const response = await fetch('/limit', { method: 'POST', body: JSON.stringify([/* orders */]) }); const result: { posted: Array<Order>; matched: Array<Order>; // Separate array for matched orders rejected: Array<Order>; } = await response.json();After:
// New response format const response = await fetch('/limit', { method: 'POST', body: JSON.stringify([/* orders */]) }); const result: { posted: Array<Order>; // Now includes both posted AND matched orders rejected: Array<Order>; } = await response.json(); // Note: matched field no longer exists - matched orders are merged into 'posted' arrayBenefits:
- Simplified response structure: Easier to process all successful orders in one array
- Reduced complexity: No need to merge
postedandmatchedarrays client-side - Clearer semantics: All successfully processed orders (whether posted to orderbook or immediately matched) are in
posted
Migration:
- Update response type to remove
matchedfield - Process all successful orders from the
postedarray (includes both posted and matched orders) - If you need to distinguish matched orders, check the
order_statefield (will befilledoropen) - Remove any client-side code that separately processed the
matchedarray
Documentation
-
Complete REST API documentation updates
- Updated
/instrumentsendpoint OpenAPI schema with newInstrumentsDataresponse type - Added detailed field descriptions for
updated_atandinstrumentsproperties - Updated endpoint description to highlight new timestamp functionality
- Updated
-
Complete WebSocket API documentation updates
- Added detailed channel description for
instrumentschannel - Added event data structures with field descriptions
- Added subscription examples for both single market and all markets scenarios
- Updated Available Channels table with new
instrumentsentry - Updated Event Types table with
instrumentsevent - Added comprehensive use cases and implementation notes
- Added detailed channel description for
[1.10.0] - 2025-10-14
Added
-
New
mmpWebSocket channel for Market Maker Protection events- Purpose: Monitor when MMP (Market Maker Protection) is triggered, temporarily freezing an account's trading when risk thresholds are exceeded
- Benefits: Real-time notifications of risk threshold violations, proactive risk management, automated trading pause awareness
- New capabilities: Track freeze status, monitor freeze duration, filter by account or trading pair
Example subscription:
{ "channel": "mmp", "query": { "smart_account_address": "0x1234567890abcdef1234567890abcdef12345678", "pair": "BTC_USDC" // optional } }Event data received:
{ "kind": "event", "type": "mmp_triggered", "timestamp_ms": 1677721600000, "data": { "smart_account_address": "0xabCDEF1234567890ABcDEF1234567890aBCDeF12", "pair_symbol": "ETH_USDC", "frozen_until": 1677721660000, "frozen_duration_seconds": 60 } }Query parameters:
smart_account_address(optional): Filter events for a specific smart accountpair(optional): Filter events for a specific trading pair (BTC_USDC, ETH_USDC, or ARB_USDC)
Use cases:
- Market makers monitoring their own MMP status
- Risk management systems tracking protection triggers
- Automated trading bots pausing operations during freeze periods
-
New
bankruptcyWebSocket channel for account bankruptcy events- Purpose: Monitor when account equity becomes negative after liquidation attempts, representing losses absorbed by the insurance fund
- Benefits: Real-time bankruptcy notifications, insurance fund impact tracking, systemic risk monitoring
- New capabilities: Track bankruptcy events by market, monitor insurance fund utilization
Example subscription:
{ "channel": "bankruptcy", "query": { "market": "ETH_USDC" // optional } }Event data received:
{ "kind": "event", "type": "bankruptcy", "timestamp_ms": 1677721600000, "data": { "marginAccountId": "550e8400-e29b-41d4-a716-446655440000", "market": "ETH_USDC" } }Query parameters:
market(optional): Filter events by trading pair (BTC_USDC, ETH_USDC, ARB_USDC, or USDC_USDC)
Use cases:
- Risk managers monitoring systemic risk indicators
- Insurance fund tracking and analysis
- Market health monitoring and alerting
Documentation
- Complete WebSocket API documentation updates
- Added detailed channel descriptions for
mmpandbankruptcychannels - Added event data structures with field descriptions
- Added subscription examples with multiple query parameter combinations
- Updated Available Channels table with new entries
- Updated Event Types table with
mmp_triggeredandbankruptcyevents
- Added detailed channel descriptions for
[1.9.0] - 2025-09-29
Added
-
Future settlement projections in risk calculations (
POST /calculate_user_risk)- New field:
future_settlement_projectionsobject containing risk metrics for future expiration dates - Benefits: Evaluate how portfolio risk evolves as options approach expiration, better risk planning for future scenarios
- Capabilities: Each settlement date includes projected margin requirements (
im,mm), risk components (matrix_risk,delta_risk,roll_risk), and complete Greeks
Example response:
{ "status": "success", "data": { "pair": "ETH_USDC", "im": 1200.00, "mm": 1000.00, "greeks": { /* current greeks */ }, "future_settlement_projections": { "2025-10-31": { "im": 1440.00, "mm": 1200.00, "matrix_risk": 960.00, "delta_risk": 180.00, "roll_risk": 60.00, "greeks": { "delta": 1.8, "gamma": 0.008, "vega": 90.0, "theta": -12.0, "rho": 4.5 } } } } } - New field:
-
New
orderbook_makerWebSocket channel for market makers- Purpose: Dedicated channel for market makers to monitor their own orders efficiently
- Benefits: Initial snapshot of all maker's active orders, real-time updates for only that maker's activity, reduced bandwidth and processing overhead
- Migration: Replaces the
makerfilter previously available inorderbook_optionsandorderbook_perpschannels
Example subscription:
{ "channel": "orderbook_maker", "query": { "maker": "0x1234567890abcdef1234567890abcdef12345678", "pair": "BTC_USDC" // optional } }Events received:
- Initial:
ob_maker_ordersevent with all active orders - Ongoing:
post_orderandcancel_orderevents for that maker only
-
Session revocation enhancements (
DELETE /session)- New capability: Delete all one-click trading sessions for an API key by omitting the
x-one-clickheader - Benefits: Bulk session cleanup, simplified session management for applications with multiple sessions
- Response: Returns count of revoked sessions
Example - Revoke all sessions:
// Without x-one-click header - revokes ALL sessions const response = await fetch('/session', { method: 'DELETE', headers: { 'x-apikey': 'your-api-key' // No x-one-click header } }); // Response: { "revokedSessions": 5 } - New capability: Delete all one-click trading sessions for an API key by omitting the
-
User tracking field in market order responses
- New field:
user_idadded to POST market order responses for analytics and tracking - Benefits: Better order attribution, enhanced analytics capabilities, improved debugging
- Location: Returned in response body after successful market order submission
- New field:
Changed
-
Breaking Change: WebSocket
makerfiltering moved to dedicated channel- Removed:
makerparameter no longer available inorderbook_optionsandorderbook_perpschannels - Replacement: Use the new
orderbook_makerchannel for maker-specific filtering
Before (deprecated):
{ "channel": "orderbook_options", "query": { "pair": "BTC_USDC", "maker": "0x1234..." // No longer supported } }After (required):
{ "channel": "orderbook_maker", "query": { "maker": "0x1234...", // Now in dedicated channel "pair": "BTC_USDC" } }Benefits: Better performance isolation, cleaner API design, optimized for market maker use cases
- Removed:
Updated
- RFQ response requirements clarified
- Clarification: RFQ responses must contain either all option orders OR exactly one perpetual order
- Validation: Cannot mix options and perpetuals in the same RFQ response
- Documentation: Enhanced examples and constraints in RFQ documentation
[1.8.1] - 2025-09-02
Added Documentation Error (Corrected in 1.13.0)
-
WebSocket trade events now include order size and fill information⚠️ Correction: This entry was documented in error. Trade events do NOT include
order_sizeorfilled_amountfields. These fields are available on order events (post_order,update_order,cancel_order), not trade events. See version 1.13.0 for the correct trade event structure.For order lifecycle tracking, subscribe to orderbook channels and use the
update_orderevent (added in 1.12.0) which provides complete order state includingfilled_amount.
[1.8.0] - 2025-08-30
Added
-
WebSocket orderbook subscription filtering by maker address
- New capability: Filter orderbook events (
post_order,cancel_order,trade) by specific market maker address - Benefits: Reduces bandwidth usage by receiving only relevant orderbook updates, enables tracking specific market makers
- Channels affected:
orderbook_options,orderbook_perps
Example:
// Subscribe to orderbook events from a specific maker only const subscription = { channel: 'orderbook_options', query: { pair: 'BTC_USDC', maker: '0x1234567890abcdef1234567890abcdef12345678' } }; - New capability: Filter orderbook events (
-
WebSocket orderbook snapshot skipping option
- New capability: Skip initial orderbook snapshot when subscribing to orderbook channels
- Benefits: Faster subscription initialization, reduced initial data transfer for clients that only need incremental updates
- Use case: Ideal for applications that maintain their own orderbook state or only need real-time updates
Example:
// Subscribe without receiving initial orderbook state const subscription = { channel: 'orderbook_perps', query: { instrument_name: 'BTC_USDC-PERPETUAL', options: { skip_snapshot: true // Only receive incremental updates } } };
Changed
-
WebSocket orderbook subscriptions now support optional
pairparameter- Breaking Change: The
pairparameter is now optional fororderbook_optionsandorderbook_perpschannels - Benefits: Subscribe to all instruments across all markets in a single subscription, simplified market-wide monitoring
Before:
// Previously required to specify a pair const subscription = { channel: 'orderbook_options', query: { pair: 'BTC_USDC', // Was required maturity: '29AUG25' } };After:
// Now can subscribe to all markets at once const subscription = { channel: 'orderbook_options', query: { // pair is now optional - omit to receive all markets maturity: '29AUG25' // Can filter by maturity across all pairs } }; // Or subscribe to absolutely everything const subscribeToAll = { channel: 'orderbook_perps', query: {} // Receives all perpetual orderbook events };Migration Guide:
- Existing subscriptions with
pairspecified will continue to work unchanged - To subscribe to all markets, simply omit the
pairparameter - Consider using the new
makerfilter orskip_snapshotoption to manage data volume when subscribing broadly
- Breaking Change: The
[1.7.0] - 2025-08-27
🔄 Changed - RFQ Response Event Improvements
Breaking Change: WebSocket rfq_response Event Split into Two Distinct Events
rfq_response Event Split into Two Distinct EventsThe single rfq_response WebSocket event has been split into two semantically distinct events for improved clarity and event handling:
rfq_post_response: Emitted when a market maker posts a new response to an RFQ request with pricingrfq_cancel_response: Emitted when a market maker cancels a previously posted RFQ response
Before:
// Single event type for both posting and cancelling
ws.on('message', (msg) => {
if (msg.type === 'rfq_response') {
// Had to check fills array to determine if it was a post or cancel
if (msg.data.fills && msg.data.fills.length > 0) {
// Handle new response
} else {
// Handle cancellation
}
}
});After:
// Distinct event types for clearer handling
ws.on('message', (msg) => {
if (msg.type === 'rfq_post_response') {
// Handle new RFQ response with pricing
const fills = msg.data.fills; // Always contains pricing data
processPricing(fills);
} else if (msg.type === 'rfq_cancel_response') {
// Handle RFQ response cancellation
const responseId = msg.data.response_id;
removePricing(responseId);
}
});Benefits:
- Clearer semantics: Event type immediately indicates the action without checking payload
- Improved type safety: TypeScript users get better type inference for each event
- Simplified event handling: No need to check fills array to determine event intent
- Better observability: Easier to track and monitor different RFQ response actions
Migration Guide:
- Update WebSocket message handlers to check for
rfq_post_responseandrfq_cancel_responseinstead ofrfq_response - Remove any logic that checks the fills array to determine if it's a cancellation
- Handle each event type with its specific business logic
Note: RFQ cancellations are now properly emitted only on the rfq channel and no longer appear on orderbook channels.
[1.6.1] - 2025-08-27
📝 Fixed - WebSocket Documentation Corrections
Corrected WebSocket Message kind Field Values
kind Field Values- Fixed documentation to accurately reflect the WebSocket message
kindfield values used in the actual implementation - Previous documentation incorrectly showed uppercase values (
"RESPONSE","EVENT") - Corrected values now show lowercase as per the codebase (
"response","event")
Before (Incorrect):
{
"kind": "RESPONSE", // ❌ Incorrect - uppercase
"type": "auth",
"id": "request-123",
"timestamp_ms": 1677721600000,
"success": true
}After (Correct):
{
"kind": "response", // ✅ Correct - lowercase
"type": "auth",
"id": "request-123",
"timestamp_ms": 1677721600000,
"success": true
}Impact:
- No functional changes to the WebSocket API behavior
- Documentation only update to match actual implementation
[1.6.0] - 2025-08-20
✨ Added - Account History Endpoint
New Endpoint: GET /account_history for Complete Trading History
GET /account_history for Complete Trading History- New public REST endpoint for retrieving comprehensive account trading history and events
- Consolidated view: Access all trades and account events (deposits, withdrawals, settlements, funding) in a single request
- Flexible filtering: Query by time range and limit results for efficient data retrieval
- Complete audit trail: Track all account activity for reconciliation and analysis
Usage Example:
// Retrieve account history with optional filters
const response = await fetch('/account_history?' + new URLSearchParams({
address: '0x9a2f0C371820e8BE3D64efb3E814808F231880ff',
start_timestamp: '1704067200', // Optional: Unix timestamp
end_timestamp: '1704153600', // Optional: Unix timestamp
count: '100' // Optional: Max records to return
}));
const data = await response.json();
// Response structure
{
address: '0x9a2f0C371820e8BE3D64efb3E814808F231880ff',
history: {
trades: [
{
trade_id: 'a1b2c3d4e5f678901234567890abcdef',
instrument_name: 'BTC_USDC-29AUG25-106000-C',
direction: 'buy',
size: 1.5,
average_price: 125.50,
realised_pnl: -5.75,
// ... full trade details including fees and greeks
}
],
account_events: [
{
action: 'deposit', // Types: deposit, withdrawal, settlement, funding
amount: 1000.0,
symbol: 'USDC',
timestamp: 1704067500,
// ... complete event details
}
]
}
}[1.5.0] - 2025-08-02
✨ Added - Enhanced Order Tracking
Optional User ID Field for Order Tracking
- Added
user_idfield to all order types for enhanced tracking and analytics:- REST Endpoints: All limit orders (
POST /limit), market orders (POST /market), combo orders (POST /combo), and RFQ orders - WebSocket Events: Trade events now include
user_idfield in data payload - Field Type: Optional string with maximum 36 characters
- Use Cases: Custom order labeling, client-side tracking, analytics categorization, portfolio grouping
- REST Endpoints: All limit orders (
Migration Example:
// Before (existing functionality continues to work)
const limitOrder = {
instrument_name: 'BTC_USDC-29AUG25-106000-C',
type: 'good_til_cancelled',
contracts: 1.5,
direction: 'buy',
price: 1000.5,
// ... other required fields
};
// After (optional user_id field available)
const limitOrder = {
instrument_name: 'BTC_USDC-29AUG25-106000-C',
type: 'good_til_cancelled',
contracts: 1.5,
direction: 'buy',
price: 1000.5,
user_id: 'portfolio_a_trade_001', // New optional field
// ... other required fields
};Benefits:
- Custom tracking: Label orders with your own identifiers for easier management
- Portfolio organization: Group orders by strategy, client, or trading session
- Analytics enhancement: Track performance metrics across custom categories
- Backwards compatible: Existing code continues to work without changes
🔧 Changed - RFQ Validation and Rate Limiting
Breaking Change: RFQ Opposite Direction Requirement
- RFQ responses now require opposite directions between taker requests and maker limit orders
- Traditional market making: Takers request one direction, makers provide liquidity in the opposite direction
- Enhanced validation: System validates direction compatibility before accepting RFQ responses
Before:
// Previously allowed (incorrect market making)
const rfqResponse = {
fills: [
[
{
instrument_name: 'BTC_USDC-29AUG25-106000-C',
contracts: 1.5,
direction: 'buy',
}, // Taker request
{
instrument_name: 'BTC_USDC-29AUG25-106000-C',
contracts: 1.5,
direction: 'buy', // Same direction - previously allowed but incorrect
price: 2500.0,
// ... other limit order fields
},
],
],
};After:
// Now required (correct market making)
const rfqResponse = {
fills: [
[
{
instrument_name: 'BTC_USDC-29AUG25-106000-C',
contracts: 1.5,
direction: 'buy',
}, // Taker request
{
instrument_name: 'BTC_USDC-29AUG25-106000-C',
contracts: 1.5,
direction: 'sell', // Opposite direction - now required
price: 2500.0,
// ... other limit order fields
},
],
],
};Benefits:
- Correct market making: Ensures proper liquidity provision patterns
- Reduced errors: Prevents mismatched trading pairs that could lead to unintended positions
- Market integrity: Aligns with traditional finance market making principles
WebSocket Rate Limiting Scope Change
- Rate limiting changed from per-API-key to per-session for WebSocket connections
- Independent limits: Each WebSocket connection now has its own 15 requests/minute limit
- Same endpoints affected:
get_ob_state_by_instrumentsandget_ob_state_by_market
Before:
// All connections using the same API key shared a single rate limit
// If you had 3 WebSocket connections with the same API key,
// they collectively shared 15 requests/minuteAfter:
// Each WebSocket connection gets its own independent rate limit
// 3 WebSocket connections = 3 × 15 = 45 total requests/minuteBenefits:
- Better scalability: Multiple connections per API key don't interfere with each other
- Fairness: Each connection gets full rate limit allocation
- Simplified management: Rate limits tied to connection lifecycle rather than API key usage
[1.4.0] - 2025-07-26
✨ Added - New Endpoint and Enhanced Features
New REST Endpoint: Index Price Retrieval
- Added
GET /index_priceendpoint for retrieving current index prices- Supported markets: BTC, ETH, ARB
- Data source: Real-time Chainlink oracle feeds via WebSocket streaming
- Response format: Direct numerical value (e.g.,
106500.25) - Authentication: API key required
- Use cases: Portfolio valuation, risk management, strategy analysis, settlement reference
WebSocket Rate Limiting Implementation
- Added per-API-key rate limiting for market data WebSocket messages:
get_ob_state_by_instruments: 15 requests per minute per API keyget_ob_state_by_market: 15 requests per minute per API key
- Enhanced error responses with reset time and remaining request information
- Sliding window algorithm with 60-second windows for fair usage distribution
WebSocket Documentation Enhancements
- Added comprehensive timestamp format clarification:
- Event wrapper timestamps (
timestamp_ms): 13-digit milliseconds for event ordering - Data payload timestamps (
timestamp): Usually 13-digit milliseconds for data-specific times - Creation timestamps (
creation_timestamp): 10-digit seconds for order/request creation
- Event wrapper timestamps (
🔧 Changed - Rate Limiting and Performance
WebSocket Rate Limiting Behavior
- Rate limits now apply per API key instead of global limits
- Enhanced rate limit responses include specific reset timing and remaining request counts
- Alternative guidance provided encouraging subscription-based real-time updates over polling
[1.3.0] - 2025-07-17
✨ Added - API Documentation Enhancements
Enhanced API Documentation Structure
- Added Key Identifier Types section to main API documentation explaining
order_idvstrade_idrelationship - Created comprehensive developer guide (
order_id_vs_trade_id.md) with detailed trading scenarios and examples
Enhanced Batch Order Constraints
- Added detailed constraint documentation for limit order batching:
- All orders must be from the same maker
- All orders must be for the same market (BTC, ETH, or ARB)
- Added comprehensive examples showing valid and invalid batch configurations
- Enhanced error response documentation with specific rejection reasons and examples
Order Cancellation Requirements
- Made
marketfield required inCancelAllOrdersRequestschema (breaking change for order cancellation) - Updated endpoint description to clarify market-specific cancellation behavior
[1.2.0] - 2025-01-10
⚠️ Removed - WebSocket Method
Deprecated get_last_trades_by_instrument WebSocket Method
get_last_trades_by_instrument WebSocket MethodThe get_last_trades_by_instrument WebSocket method has been removed. This method was previously used to retrieve historical trade data through the WebSocket connection.
Migration Guide
Use the REST API endpoint instead:
// Before (WebSocket)
ws.send(
JSON.stringify({
type: 'get_last_trades_by_instrument',
instrument_name: 'BTC_USDC-29AUG25-106000-C',
start_timestamp: 1677721600000,
end_timestamp: 1677808000000,
}),
);
// After (REST API)
const response = await fetch(
`/last_trades_by_instrument?instrument_name=${instrumentName}&start_timestamp=${startTimestamp}&end_timestamp=${endTimestamp}`,
{
headers: {
'x-apikey': API_KEY,
'Content-Type': 'application/json',
},
},
);
const trades = await response.json();Benefits
- Better Performance: REST API is optimized for historical data queries
- Caching: REST responses can be cached by CDNs and browsers
- Simpler Integration: No need to maintain WebSocket connection for historical data
- Standard HTTP: Use familiar HTTP methods and status codes for error handling
📚 Enhanced - Order Submission Documentation
Improved Code Examples and Field Clarifications
Enhanced the order submission documentation with clearer examples and important field requirements:
- Signature Requirements: Clearly documented that both
signatureandsignature_deadlineare required when not using one-click sessions - Separate Examples: Added distinct examples for options and perpetual orders showing the correct field usage
- Field Clarifications:
- Options orders use
contractsfield - Perpetual orders use
amountfield - The
takerfield is optional and defaults to zero address (any taker)
- Options orders use
New Code Examples
// Options Order Example
const optionsOrder = {
instrument_name: 'BTC_USDC-29AUG25-106000-C',
type: 'good_til_cancelled',
contracts: 1.5, // For options
direction: 'buy',
price: 2500,
// ... other fields
};
// Perpetuals Order Example
const perpsOrder = {
instrument_name: 'BTC_USDC-PERPETUAL',
type: 'good_til_cancelled',
amount: 10000, // For perpetuals
direction: 'buy',
price: 45000,
// ... other fields
};🔧 Enhanced - Error Response Documentation
Detailed Validation Error Structure
Order rejection responses now include detailed validation error information when the rejection reason is "invalid request":
{
"rejected_orders": [
{
"order_id": "abc123",
"reason": "invalid request",
"error": [
{
"instancePath": "/orders/0/contracts",
"schemaPath": "#/properties/contracts/minimum",
"keyword": "minimum",
"params": { "limit": 0 },
"message": "must be >= 0"
}
]
}
]
}Benefits
- Precise Error Location:
instancePathshows exactly which field failed validation - Clear Error Messages: Human-readable messages explain what went wrong
- Faster Debugging: Developers can quickly identify and fix validation issues
[1.1.1] - 2025-01-09
🔧 Fixed - API Header Standardization
API Key Header Casing
Standardized the API key header name to use consistent lowercase formatting:
Before:
X-APIKey: your-api-key-hereAfter:
x-apikey: your-api-key-hereMigration Guide
Update your API requests to use the lowercase header:
// Before
const response = await fetch('/instruments?market=ETH', {
headers: {
'X-APIKey': API_KEY,
'Content-Type': 'application/json',
},
});
// After
const response = await fetch('/instruments?market=ETH', {
headers: {
'x-apikey': API_KEY,
'Content-Type': 'application/json',
},
});Benefits
- Consistent Header Casing: All headers now follow lowercase convention
- HTTP/2 Compatibility: Lowercase headers are required for HTTP/2
- Framework Alignment: Matches standard practices across modern APIs
🔧 Fixed - WebSocket Event Types
Corrected Event Type Naming
Fixed inconsistent event type naming in WebSocket documentation:
Before:
{
"type": "withdraw",
"action": "withdraw"
}After:
{
"type": "withdrawal",
"action": "withdrawal"
}Migration Guide
Update your WebSocket event handlers:
// Before
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'withdraw') {
// Handle withdrawal event
}
};
// After
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'withdrawal') {
// Handle withdrawal event
}
};Benefits
- Consistency: Event types now match the implementation and enum definitions
- Clarity: "withdrawal" is more descriptive than "withdraw"
- Type Safety: Consistent naming improves TypeScript integration
[1.1.0] - 2025-01-04
🚀 Enhanced - Account State Endpoint
Improved Risk & Market Data
The /account_state/{account} endpoint now provides significantly more detailed information to support advanced trading strategies and risk management.
Breaking Changes
-
Response Structure Flattened: The
summarywrapper object has been removed. Account state fields are now directly accessible at the root level of each margin account.Before:
{ "margin_accounts": [ { "pair": "ETH_USDC", "summary": { "equity": 10500.0, "im": 2000.0, "mm": 1500.0, "pnl": 500.0 }, "positions": [...] } ] }After:
{ "margin_accounts": [ { "pair": "ETH_USDC", "timestamp": 1677721600000, "margin_account": 12345, "equity": 10500.0, "im": 2000.0, "mm": 1500.0, "unrealised_pnl": 500.0, // ... additional fields "positions": [...] } ] }
New Response Fields
timestamp: Unix timestamp when the account state was calculatedmargin_account: Unique margin account identifiermatrix_risk: Portfolio risk matrix component for comprehensive risk assessmentdelta_risk: Delta risk component measuring directional exposureroll_risk: Roll risk component for near-expiry option positionsportfolio_greeks: Portfolio-level Greeks aggregationdelta: Portfolio delta exposuregamma: Portfolio gamma exposurevega: Portfolio vega exposuretheta: Portfolio theta (time decay)rho: Portfolio rho (interest rate sensitivity)
Enhanced Position Data
Positions now include real-time market data and risk metrics:
For Options:
instrument_type: Always "option" for option positionsmark_price: Current mark price of the optionmark_iv: Mark implied volatilitymark_interest: Mark interest rate used in pricingposition_greeks: Position-level Greeksdelta,gamma,theta,vega,rho
For Perpetuals:
instrument_type: Always "perp" for perpetual positionsmark_price: Current mark price of the perpetualcurrent_funding_rate: Current funding rateposition_greeks: Position-level Greeksdelta
Migration Guide
Update your code to access account state fields directly:
// Before
const equity = accountState.margin_accounts[0].summary.equity;
const im = accountState.margin_accounts[0].summary.im;
// After
const equity = accountState.margin_accounts[0].equity;
const im = accountState.margin_accounts[0].im;
// New capabilities
const portfolioGreeks = accountState.margin_accounts[0].portfolio_greeks;
const riskBreakdown = {
matrix: accountState.margin_accounts[0].matrix_risk,
delta: accountState.margin_accounts[0].delta_risk,
roll: accountState.margin_accounts[0].roll_risk,
};Benefits
- Better Risk Management: Detailed risk component breakdown enables more sophisticated risk monitoring
- Real-time Market Data: Position-level mark prices and Greeks for accurate P&L calculation
- Reduced API Calls: Mark prices and Greeks available directly without additional requests
- Enhanced Analytics: Portfolio-level Greeks aggregation for portfolio analysis
- Streamlined Integration: Simplified response structure reduces parsing complexity
For questions or support, please contact our development team or visit our documentation.
