Skip to content

Get Open Orders (WebSocket)

Retrieve all currently open orders for the authenticated subaccount through the WebSocket connection. This method returns only active orders (not filled or cancelled), with optional filtering by symbol and pagination.

Request-Response vs Subscriptions

This method provides on-demand snapshots of open order data. For real-time updates when orders change, use SubAccount Updates Subscription.

MethodPurposeWhen to Use
getOpenOrdersActive orders snapshotInitial load, order management, UI refresh
Order Updates SubscriptionReal-time notificationsLive UI updates, event handling

Endpoint

ws.send() wss://api.synthetix.io/v1/ws/trade

Request

Request Format

{
  "id": "openorders-1",
  "method": "post",
  "params": {
    "action": "getOpenOrders",
    "subAccountId": "1867542890123456789",
    "symbol": "BTC-USDT",
    "limit": 50,
    "offset": 0,
    "expiresAfter": 1704067500,
    "signature": {
      "v": 28,
      "r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
    }
  }
}

Parameters

Request Parameters

ParameterTypeRequiredDescription
idstringYesClient-generated unique request identifier
methodstringYesMust be "post"
paramsobjectYesContains all parameters for the request

Params Object

ParameterTypeRequiredDescription
actionstringYesMust be "getOpenOrders"
subAccountIdstringYesSubaccount identifier
symbolstringNoFilter orders by specific market symbol (e.g., "BTC-USDT")
limitintegerNoMaximum number of orders to return (default: 50)
offsetintegerNoNumber of orders to skip for pagination (default: 0)
expiresAfterintegerNoOptional expiration timestamp in milliseconds
signatureobjectYesEIP-712 signature using SubAccountAction type
Important Notes:
  • This endpoint uses SubAccountAction EIP-712 type (no nonce required, only expiresAfter is optional)
  • Returns only active orders (placed, partially filled)
  • Does not include filled, cancelled, or rejected orders

EIP-712 Signature

const domain = {
  name: "Synthetix",
  version: "1",
  chainId: 1,
  verifyingContract: "0x0000000000000000000000000000000000000000"
};
 
const types = {
  SubAccountAction: [
    { name: "subAccountId", type: "uint256" },
    { name: "action", type: "string" },
    { name: "expiresAfter", type: "uint256" }
  ]
};
 
const message = {
  subAccountId: "1867542890123456789",
  action: "getOpenOrders",
  expiresAfter: 0
};
 
const signature = await signer._signTypedData(domain, types, message);

Response Format

Success Response

{
  "id": "openorders-1",
  "status": 200,
  "result": {
    "status": "success",
    "response": [
      {
        "order": {
          "venueId": "1958787130134106112",
          "clientId": "cli-1958787130134106112"
        },
        "orderId": "1958787130134106112",
        "symbol": "BTC-USDT",
        "side": "buy",
        "type": "LIMIT",
        "quantity": "0.1",
        "price": "45000.00",
        "triggerPrice": "",
        "triggerPriceType": "",
        "timeInForce": "GTC",
        "reduceOnly": false,
        "postOnly": false,
        "closePosition": false,
        "createdTime": 1755846234000,
        "updatedTime": 1755846234000,
        "filledQuantity": "0.0",
        "takeProfitOrder": {
          "venueId": "1958787130134106115",
          "clientId": "cli-1958787130134106115"
        },
        "takeProfitOrderId": "1958787130134106115",
        "stopLossOrder": {
          "venueId": "1958787130134106116",
          "clientId": "cli-1958787130134106116"
        },
        "stopLossOrderId": "1958787130134106116"
      },
      {
        "order": {
          "venueId": "1958787130134106113",
          "clientId": "cli-1958787130134106113"
        },
        "orderId": "1958787130134106113",
        "symbol": "ETH-USDT",
        "side": "sell",
        "type": "LIMIT",
        "quantity": "2.0",
        "price": "2800.00",
        "triggerPrice": "",
        "triggerPriceType": "",
        "timeInForce": "GTC",
        "reduceOnly": false,
        "postOnly": true,
        "closePosition": false,
        "createdTime": 1755846235000,
        "updatedTime": 1755846235000,
        "filledQuantity": "0.5",
        "takeProfitOrderId": "",
        "stopLossOrderId": ""
      }
    ]
  }
}

Empty Result

{
  "id": "openorders-1",
  "status": 200,
  "result": {
    "status": "success",
    "response": []
  }
}

Error Response

{
  "id": "openorders-1",
  "status": 400,
  "result": null,
  "error": {
    "code": 400,
    "message": "Failed to get open orders"
  }
}

Order Object Fields

FieldTypeDescription
orderobjectCanonical order identifier object
order.venueIdstringCanonical venue-generated order identifier
order.clientIdstringOptional client-provided order identifier
orderIdstringDeprecated legacy order identifier
symbolstringTrading pair symbol (e.g., "BTC-USDT")
sidestringOrder side: "buy" or "sell"
typestringOrder type (e.g., "LIMIT", "MARKET")
quantitystringTotal order quantity
pricestringOrder price (empty for market orders)
triggerPricestringTrigger price for conditional orders
triggerPriceTypestringTrigger price type: "mark", "last", or "index"
timeInForcestringTime in force: "GTC", "IOC", or "FOK"
reduceOnlybooleanWhether order can only reduce position
postOnlybooleanWhether order must be maker (no immediate match)
closePositionbooleanWhether order closes entire position
createdTimeintegerOrder creation timestamp (Unix milliseconds)
updatedTimeintegerLast update timestamp (Unix milliseconds)
filledQuantitystringQuantity that has been filled
takeProfitOrderobjectCanonical linked take-profit order identifier object
takeProfitOrderIdstringDeprecated linked take-profit venue ID
stopLossOrderobjectCanonical linked stop-loss order identifier object
stopLossOrderIdstringDeprecated linked stop-loss venue ID

Migration Note: Use order.venueId as canonical. orderId, takeProfitOrderId, and stopLossOrderId are deprecated compatibility fields.

Note on TP/SL Fields: When orders are placed with normalTpsl or positionTpsl grouping, the entry order will contain takeProfitOrder and stopLossOrder objects linking to associated TP/SL trigger orders.

Code Examples

Get All Open Orders

{
  "id": "openorders-all",
  "method": "post",
  "params": {
    "action": "getOpenOrders",
    "subAccountId": "1867542890123456789",
    "expiresAfter": 1704067500,
    "signature": { "v": 28, "r": "0x...", "s": "0x..." }
  }
}

Get Open Orders for Specific Market

{
  "id": "openorders-btc",
  "method": "post",
  "params": {
    "action": "getOpenOrders",
    "subAccountId": "1867542890123456789",
    "symbol": "BTC-USDT",
    "expiresAfter": 1704067500,
    "signature": { "v": 28, "r": "0x...", "s": "0x..." }
  }
}

Get Open Orders with Pagination

{
  "id": "openorders-paginated",
  "method": "post",
  "params": {
    "action": "getOpenOrders",
    "subAccountId": "1867542890123456789",
    "limit": 100,
    "offset": 0,
    "expiresAfter": 1704067500,
    "signature": { "v": 28, "r": "0x...", "s": "0x..." }
  }
}

Implementation Example

class OpenOrdersQuery {
  constructor(ws) {
    this.ws = ws;
    this.pendingRequests = new Map();
  }
 
  async getOpenOrders(options = {}) {
    const {
      subAccountId,
      symbol = null,
      limit = 50,
      offset = 0,
      expiresAfter = 0,
      signature
    } = options;
 
    const request = {
      id: `openorders-${Date.now()}`,
      method: "post",
      params: {
        action: "getOpenOrders",
        subAccountId: subAccountId.toString(),
        expiresAfter,
        signature
      }
    };
 
    // Add optional filters
    if (symbol) request.params.symbol = symbol;
    if (limit) request.params.limit = limit;
    if (offset) request.params.offset = offset;
 
    return this.sendRequest(request);
  }
 
  sendRequest(request) {
    return new Promise((resolve, reject) => {
      this.pendingRequests.set(request.id, { resolve, reject });
      this.ws.send(JSON.stringify(request));
 
      setTimeout(() => {
        if (this.pendingRequests.has(request.id)) {
          this.pendingRequests.delete(request.id);
          reject(new Error('Request timeout'));
        }
      }, 10000);
    });
  }
 
  handleResponse(response) {
    const pending = this.pendingRequests.get(response.id);
    if (pending) {
      this.pendingRequests.delete(response.id);
      if (response.error) {
        pending.reject(new Error(response.error.message));
      } else {
        pending.resolve(response.result.response);
      }
    }
  }
}
 
// Usage
const query = new OpenOrdersQuery(ws);
const openOrders = await query.getOpenOrders({
  subAccountId: "1867542890123456789",
  symbol: "BTC-USDT",
  signature: { v: 28, r: "0x...", s: "0x..." }
});
console.log(`Found ${openOrders.length} open orders`);

Comparison with getOrderHistory

FeaturegetOpenOrdersgetOrderHistory
PurposeCurrently active orders onlyAll orders with comprehensive history
Time FilteringNot supportedfromTime/toTime range
Status FilteringNot supported (active only)Multiple status filters
Default ScopeActive orders onlyAll orders (any status)
Use CaseReal-time order managementHistorical analysis and reporting
PerformanceFaster (smaller dataset)May be slower with large history

Integration with Subscriptions

Combine request-response queries with subscriptions for complete order management:

class OrderManager {
  constructor(ws, subAccountId) {
    this.ws = ws;
    this.subAccountId = subAccountId;
    this.openOrders = new Map();
  }
 
  async initialize() {
    // 1. Get initial open orders
    const request = {
      id: "init-openorders",
      method: "post",
      params: {
        action: "getOpenOrders",
        subAccountId: this.subAccountId,
        expiresAfter: 0,
        signature: { /* ... */ }
      }
    };
    this.ws.send(JSON.stringify(request));
 
    // 2. Subscribe to real-time updates
    this.ws.send(JSON.stringify({
      id: "subscribe-orders",
      method: "subscribe",
      params: {
        type: "subAccountUpdates",
        subAccountId: this.subAccountId
      }
    }));
  }
 
  handleOrderUpdate(update) {
    const { eventType } = update.data;
    const orderKey = update.data.order?.venueId || update.data.orderId;
 
    if (eventType === 'cancelled' || eventType === 'filled') {
      this.openOrders.delete(orderKey);
    } else if (eventType === 'placed' || eventType === 'partially_filled') {
      this.openOrders.set(orderKey, update.data);
    }
  }
}

Validation Rules

  • Subaccount ID must be valid and accessible
  • Limit must be between 1 and 100 (default: 50)
  • Offset must be non-negative (default: 0)
  • Symbol must be a valid trading pair (if specified)
Error CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes

Next Steps