Skip to main content

openOrders

Get all open limit orders for a user on Hyperliquid perpetual markets.

Why Hyperliquid? Build on the dominant perpetuals DEX with 70% market share, $2.7T+ lifetime volume, and $2B TVL with 200K orders/second throughput, zero gas fees, sub-second finality, and fully onchain Central Limit Order Book (CLOB).

When to Use This Endpoint#

The openOrders endpoint is essential for traders, trading platforms, and market makers who need to:

  • Order Management — Monitor and manage active limit orders
  • Trading Bots — Track order status and execution
  • Market Making — Monitor spread and order book participation
  • Portfolio Management — Track pending orders across multiple markets

Request#

Endpoint#

POST https://api-hyperliquid-mainnet-info.n.dwellir.com/info

Headers#

HeaderValueRequired
Content-Typeapplication/jsonYes
X-Api-KeyYour API keyYes

Parameters#

ParameterTypeRequiredDescription
typestringYesMust be "openOrders"
userstringYesUser's Ethereum wallet address

Example Request#

{
"type": "openOrders",
"user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}

Response#

Success Response#

[
{
"coin": "BTC",
"side": "B",
"limitPx": "69043.0",
"sz": "0.29596",
"oid": 316509475419,
"timestamp": 1770639841704,
"origSz": "0.29596",
"cloid": "0x00000000000000000000019c4151ce32"
},
{
"coin": "ETH",
"side": "A",
"limitPx": "2034.3",
"sz": "12.1703",
"oid": 316509474405,
"timestamp": 1770639841704,
"origSz": "12.1703",
"cloid": "0x00000000000000000000019c4151ce2f"
}
]

Response Fields#

The response is an array of order objects. Each order contains:

FieldTypeDescription
coinstringTrading pair symbol (e.g., "BTC", "ETH")
sidestringOrder side: "B" for buy, "A" for ask/sell
limitPxstringLimit price for the order
szstringCurrent remaining order size
oidintegerUnique order ID
timestampintegerOrder creation timestamp in milliseconds
origSzstringOriginal order size when placed
cloidstringClient order ID (hexadecimal string)

Code Examples#

curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/info' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"type": "openOrders",
"user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'

Common Use Cases#

1. Monitor Order Fill Progress#

Track how much of each order has been filled:

async function getOrderFillProgress(userAddress) {
const orders = await getOpenOrders(userAddress);

return orders.map(order => {
const orig = parseFloat(order.origSz);
const remaining = parseFloat(order.sz);
const filled = orig - remaining;
const fillPercent = (filled / orig) * 100;

return {
orderId: order.oid,
coin: order.coin,
side: order.side === 'B' ? 'BUY' : 'SELL',
price: parseFloat(order.limitPx),
originalSize: orig,
remainingSize: remaining,
filledSize: filled,
fillPercent: fillPercent.toFixed(2),
isPartiallyFilled: fillPercent > 0 && fillPercent < 100
};
});
}

// Usage
const progress = await getOrderFillProgress('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
const partialFills = progress.filter(o => o.isPartiallyFilled);
console.log(`${partialFills.length} partially filled orders`);

2. Calculate Total Order Book Exposure#

Calculate total capital committed in open orders:

async function calculateOrderExposure(userAddress) {
const orders = await getOpenOrders(userAddress);

const totalExposure = orders.reduce((sum, order) => {
const size = parseFloat(order.sz);
const price = parseFloat(order.limitPx);
return sum + (size * price);
}, 0);

const byMarket = orders.reduce((acc, order) => {
const size = parseFloat(order.sz);
const price = parseFloat(order.limitPx);
const exposure = size * price;

if (!acc[order.coin]) {
acc[order.coin] = { buy: 0, sell: 0, total: 0 };
}

if (order.side === 'B') {
acc[order.coin].buy += exposure;
} else {
acc[order.coin].sell += exposure;
}
acc[order.coin].total += exposure;

return acc;
}, {});

return {
totalExposure: totalExposure,
byMarket: byMarket,
orderCount: orders.length
};
}

3. Find Stale Orders#

Identify orders that have been open for a long time:

async function findStaleOrders(userAddress, hoursThreshold = 24) {
const orders = await getOpenOrders(userAddress);
const now = Date.now();
const thresholdMs = hoursThreshold * 60 * 60 * 1000;

const staleOrders = orders.filter(order => {
return (now - order.timestamp) > thresholdMs;
});

return staleOrders.map(order => ({
orderId: order.oid,
coin: order.coin,
side: order.side === 'B' ? 'BUY' : 'SELL',
price: order.limitPx,
size: order.sz,
ageHours: ((now - order.timestamp) / (1000 * 60 * 60)).toFixed(1)
}));
}

// Usage
const stale = await findStaleOrders('0x63E8c7C149556D5f34F833419A287bb9Ef81487f', 48);
console.log(`${stale.length} orders older than 48 hours`);
stale.forEach(o => {
console.log(`${o.coin} ${o.side} @ $${o.price} (${o.ageHours}h old)`);
});

4. Group Orders by Market#

Organize orders by trading pair:

async function groupOrdersByMarket(userAddress) {
const orders = await getOpenOrders(userAddress);

const grouped = orders.reduce((acc, order) => {
if (!acc[order.coin]) {
acc[order.coin] = {
buy: [],
sell: [],
totalBuySize: 0,
totalSellSize: 0
};
}

const side = order.side === 'B' ? 'buy' : 'sell';
acc[order.coin][side].push(order);

if (side === 'buy') {
acc[order.coin].totalBuySize += parseFloat(order.sz);
} else {
acc[order.coin].totalSellSize += parseFloat(order.sz);
}

return acc;
}, {});

return grouped;
}

// Usage
const byMarket = await groupOrdersByMarket('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
Object.entries(byMarket).forEach(([coin, data]) => {
console.log(`\n${coin}:`);
console.log(` ${data.buy.length} buy orders (${data.totalBuySize} total)`);
console.log(` ${data.sell.length} sell orders (${data.totalSellSize} total)`);
});

5. Order Management Dashboard#

Create a comprehensive order dashboard:

async function getOrderDashboard(userAddress) {
const orders = await getOpenOrders(userAddress);

const now = Date.now();
const stats = {
totalOrders: orders.length,
buyOrders: orders.filter(o => o.side === 'B').length,
sellOrders: orders.filter(o => o.side === 'A').length,
markets: [...new Set(orders.map(o => o.coin))],
partiallyFilled: orders.filter(o => o.sz !== o.origSz).length,
averageAge: orders.reduce((sum, o) => sum + (now - o.timestamp), 0) / orders.length / (1000 * 60 * 60)
};

console.log('=== Order Dashboard ===');
console.log(`Total Orders: ${stats.totalOrders}`);
console.log(` Buy: ${stats.buyOrders}`);
console.log(` Sell: ${stats.sellOrders}`);
console.log(`Markets: ${stats.markets.join(', ')}`);
console.log(`Partially Filled: ${stats.partiallyFilled}`);
console.log(`Average Age: ${stats.averageAge.toFixed(1)} hours`);

return stats;
}

Error Handling#

Common Errors#

ErrorCauseSolution
401 UnauthorizedInvalid API keyVerify your API key is correct
400 Bad RequestMissing or invalid user addressEnsure valid Ethereum address format
429 Too Many RequestsRate limit exceededImplement request throttling
500 Internal Server ErrorServer issueRetry with exponential backoff

Error Response Example#

{
"error": "Missing required parameter: user",
"code": "MISSING_PARAMETER"
}

Robust Error Handling#

async function safeGetOpenOrders(userAddress, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await getOpenOrders(userAddress);
} catch (error) {
if (error.response?.status === 429) {
// Rate limit - exponential backoff
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
} else if (error.response?.status === 400) {
throw new Error('Invalid user address');
} else if (i === maxRetries - 1) {
throw error;
}
}
}
}

Best Practices#

  1. Poll at appropriate intervals — Poll every 5-10 seconds for active trading, less frequently for monitoring
  2. Handle empty arrays — User may have no open orders
  3. Validate addresses — Ensure user addresses are valid Ethereum addresses
  4. Track order IDs — Use order IDs to track specific orders across polls
  5. Monitor fill rates — Alert when orders are partially filled

Access real-time Hyperliquid order data with Dwellir's HyperCore Info Endpoint. Get your API key →