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.
| Method | Purpose | When to Use |
|---|---|---|
getOpenOrders | Active orders snapshot | Initial load, order management, UI refresh |
| Order Updates Subscription | Real-time notifications | Live UI updates, event handling |
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "post" |
params | object | Yes | Contains all parameters for the request |
Params Object
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "getOpenOrders" |
subAccountId | string | Yes | Subaccount identifier |
symbol | string | No | Filter orders by specific market symbol (e.g., "BTC-USDT") |
limit | integer | No | Maximum number of orders to return (default: 50) |
offset | integer | No | Number of orders to skip for pagination (default: 0) |
expiresAfter | integer | No | Optional expiration timestamp in milliseconds |
signature | object | Yes | EIP-712 signature using SubAccountAction type |
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required, onlyexpiresAfteris 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": [
{
"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",
"takeProfitOrderId": "1958787130134106115",
"stopLossOrderId": "1958787130134106116"
},
{
"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
| Field | Type | Description |
|---|---|---|
orderId | string | Unique order identifier (uint64 as string) |
symbol | string | Trading pair symbol (e.g., "BTC-USDT") |
side | string | Order side: "buy" or "sell" |
type | string | Order type (e.g., "LIMIT", "MARKET") |
quantity | string | Total order quantity |
price | string | Order price (empty for market orders) |
triggerPrice | string | Trigger price for conditional orders |
triggerPriceType | string | Trigger price type: "mark", "last", or "index" |
timeInForce | string | Time in force: "GTC", "IOC", or "FOK" |
reduceOnly | boolean | Whether order can only reduce position |
postOnly | boolean | Whether order must be maker (no immediate match) |
closePosition | boolean | Whether order closes entire position |
createdTime | integer | Order creation timestamp (Unix milliseconds) |
updatedTime | integer | Last update timestamp (Unix milliseconds) |
filledQuantity | string | Quantity that has been filled |
takeProfitOrderId | string | ID of linked take-profit order (empty string if none) |
stopLossOrderId | string | ID of linked stop-loss order (empty string if none) |
Note on TP/SL Fields: When orders are placed with normalTpsl or positionTpsl grouping, the entry order will contain takeProfitOrderId and stopLossOrderId linking to the 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
| Feature | getOpenOrders | getOrderHistory |
|---|---|---|
| Purpose | Currently active orders only | All orders with comprehensive history |
| Time Filtering | Not supported | fromTime/toTime range |
| Status Filtering | Not supported (active only) | Multiple status filters |
| Default Scope | Active orders only | All orders (any status) |
| Use Case | Real-time order management | Historical analysis and reporting |
| Performance | Faster (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, orderId } = update.data;
if (eventType === 'cancelled' || eventType === 'filled') {
this.openOrders.delete(orderId);
} else if (eventType === 'placed' || eventType === 'partially_filled') {
this.openOrders.set(orderId, 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 | Description |
|---|---|
| Invalid signature | EIP-712 signature validation failed |
| Invalid market symbol | Market symbol not recognized |
| Nonce already used | Nonce must be greater than previous value |
| Rate limit exceeded | Too many requests in time window |
| Request expired | expiresAfter timestamp has passed |
Next Steps
- SubAccount Updates Subscription - Real-time order change notifications
- Get Order History - Query historical orders with filters
- Cancel Orders - Cancel open orders
- REST Alternative - REST API comparison