Skip to main content

batchClearinghouseStates

Custom Endpoint

Batch query perpetual account states for multiple users in a single request. This is a custom endpoint exclusive to Dwellir's HyperCore REST API — it is not available on standard Hyperliquid nodes.

When to Use This Endpoint#

The batchClearinghouseStates endpoint is designed for applications that need account state for many users at once. It fans out individual clearinghouseState calls concurrently and aggregates the results, so you don't need to manage your own fan-out and error handling.

  • Portfolio Dashboards — Fetch account states for all tracked wallets in one call
  • Risk Monitoring — Monitor margin health across a fleet of trading accounts
  • Fund Management — Aggregate position data across multiple sub-accounts or strategies
  • Multi-DEX Analytics — Query all DEXes for each user with a single ALL_DEXES request

Request#

Endpoint#

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

Headers#

HeaderValueRequired
Content-Typeapplication/jsonYes

Parameters#

ParameterTypeRequiredDescription
typestringYesMust be "batchClearinghouseStates"
usersstring[]YesNon-empty list of wallet addresses
dexstringNoDEX name. Omit for native DEX. Set to "ALL_DEXES" to query all DEXes.

User Limits#

ModeMax UsersDescription
Single-DEX (no dex or a named DEX)1000 (default)One upstream call per user
ALL_DEXES100 (default)Lower limit because total calls = users × DEXes

Example Requests#

Native DEX (no dex field):

{
"type": "batchClearinghouseStates",
"users": [
"0x00f2548cf639e54420e501a35346e8458989e6bd",
"0x010461c14e146ac35fe42271bdc1134ee31c703a",
"0x02159593e155250288a7a1dd5257fc217601ceee"
]
}

Named DEX:

{
"type": "batchClearinghouseStates",
"users": [
"0x00f2548cf639e54420e501a35346e8458989e6bd",
"0x010461c14e146ac35fe42271bdc1134ee31c703a"
],
"dex": "xyz"
}

All DEXes:

{
"type": "batchClearinghouseStates",
"users": [
"0x00f2548cf639e54420e501a35346e8458989e6bd",
"0x010461c14e146ac35fe42271bdc1134ee31c703a"
],
"dex": "ALL_DEXES"
}

Response — Single DEX#

Both fields are always present. Order matches input order.

FieldTypeDescription
successful_states[address, state][]Array of two-element tuples. address is the wallet address; state is the raw upstream clearinghouseState object.
failed_walletsstring[]Addresses whose upstream call failed (timeout, non-200, etc.).

Success Response#

{
"successful_states": [
[
"0x00f2548cf639e54420e501a35346e8458989e6bd",
{
"marginSummary": {
"accountValue": "0.0",
"totalNtlPos": "0.0",
"totalRawUsd": "0.0",
"totalMarginUsed": "0.0"
},
"crossMarginSummary": {
"accountValue": "0.0",
"totalNtlPos": "0.0",
"totalRawUsd": "0.0",
"totalMarginUsed": "0.0"
},
"crossMaintenanceMarginUsed": "0.0",
"withdrawable": "0.0",
"assetPositions": [],
"time": 1771587392044
}
],
[
"0x010461c14e146ac35fe42271bdc1134ee31c703a",
{
"marginSummary": {
"accountValue": "0.0",
"totalNtlPos": "0.0",
"totalRawUsd": "0.0",
"totalMarginUsed": "0.0"
},
"crossMarginSummary": {
"accountValue": "0.0",
"totalNtlPos": "0.0",
"totalRawUsd": "0.0",
"totalMarginUsed": "0.0"
},
"crossMaintenanceMarginUsed": "0.0",
"withdrawable": "0.0",
"assetPositions": [],
"time": 1771587392044
}
]
],
"failed_wallets": []
}

Partial Failure Response#

If some calls fail, those addresses appear in failed_wallets:

{
"successful_states": [
[
"0x00f2548cf639e54420e501a35346e8458989e6bd",
{
"marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMaintenanceMarginUsed": "0.0",
"withdrawable": "0.0",
"assetPositions": [],
"time": 1771587392044
}
]
],
"failed_wallets": ["0x010461c14e146ac35fe42271bdc1134ee31c703a"]
}

Response — ALL_DEXES#

When dex is set to "ALL_DEXES", the response shape changes. Each user's state is an object keyed by DEX name.

FieldTypeDescription
successful_states[address, dex_map][]Array of two-element tuples. dex_map is an object keyed by DEX name, each value being the clearinghouseState for that DEX.
failed_walletsstring[]Addresses where all DEX calls failed.

Key semantics:

  • The native DEX appears under the key "native".
  • Partial success: if some DEX calls succeed and others fail for a user, the user is included in successful_states with only the DEXes that responded. They do not appear in failed_wallets.
  • DEX truncation: if the chain reports more DEXes than max_dexes, the list is silently truncated. The response may not cover every DEX on the chain.

ALL_DEXES Response Example#

{
"successful_states": [
[
"0x00f2548cf639e54420e501a35346e8458989e6bd",
{
"native": {
"marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMaintenanceMarginUsed": "0.0",
"withdrawable": "0.0",
"assetPositions": [],
"time": 1771587392044
},
"xyz": {
"marginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMarginSummary": { "accountValue": "0.0", "totalNtlPos": "0.0", "totalRawUsd": "0.0", "totalMarginUsed": "0.0" },
"crossMaintenanceMarginUsed": "0.0",
"withdrawable": "0.0",
"assetPositions": [],
"time": 1771587392044
}
}
]
],
"failed_wallets": ["0x010461c14e146ac35fe42271bdc1134ee31c703a"]
}

Code Examples#

curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/API_KEY/info' \
-H 'Content-Type: application/json' \
-d '{
"type": "batchClearinghouseStates",
"users": [
"0x00f2548cf639e54420e501a35346e8458989e6bd",
"0x010461c14e146ac35fe42271bdc1134ee31c703a",
"0x02159593e155250288a7a1dd5257fc217601ceee"
]
}'

Common Use Cases#

1. Multi-Account Dashboard#

Fetch and display account states for a set of tracked wallets:

async function getMultiAccountDashboard(wallets) {
const result = await getBatchClearinghouseStates(wallets);

const dashboard = result.successful_states.map(([address, state]) => ({
address,
accountValue: parseFloat(state.marginSummary.accountValue),
marginUsed: parseFloat(state.marginSummary.totalMarginUsed),
withdrawable: parseFloat(state.marginSummary.withdrawable),
positions: state.assetPositions.length
}));

const totalValue = dashboard.reduce((sum, a) => sum + a.accountValue, 0);
console.log(`Total across ${dashboard.length} accounts: $${totalValue.toFixed(2)}`);

if (result.failed_wallets.length > 0) {
console.warn(`Failed to fetch: ${result.failed_wallets.join(', ')}`);
}

return dashboard;
}

2. Cross-DEX Position Aggregation#

Query all DEXes for a set of users and aggregate positions:

async function getCrossDexPositions(wallets) {
const result = await getBatchClearinghouseStates(wallets, 'ALL_DEXES');

for (const [address, dexMap] of result.successful_states) {
console.log(`\n=== ${address} ===`);
for (const [dexName, state] of Object.entries(dexMap)) {
const value = parseFloat(state.marginSummary.accountValue);
const positions = state.assetPositions.length;
console.log(` ${dexName}: $${value.toFixed(2)} (${positions} positions)`);
}
}
}

3. Batch Risk Monitoring#

Monitor margin utilization across many accounts and flag those at risk:

async function batchRiskCheck(wallets) {
const result = await getBatchClearinghouseStates(wallets);
const alerts = [];

for (const [address, state] of result.successful_states) {
const margin = state.marginSummary;
const accountValue = parseFloat(margin.accountValue);
const marginUsed = parseFloat(margin.totalMarginUsed);
const utilization = accountValue > 0 ? (marginUsed / accountValue) * 100 : 0;

if (utilization > 80) {
alerts.push({ address, utilization: utilization.toFixed(2), accountValue });
}
}

// Also flag wallets that failed to respond
for (const address of result.failed_wallets) {
alerts.push({ address, error: 'Failed to fetch state' });
}

return alerts;
}

Error Handling#

Errors Specific to This Endpoint#

ConditionStatusBody
Invalid JSON body400{"error":"invalid JSON body"}
Missing or empty users400{"error":"users must not be empty"}
Too many users (single-DEX)413{"error":"too many users"}
Too many users (ALL_DEXES)413{"error":"too many users for ALL_DEXES"}
perpDexs upstream timeout504{"error":"upstream timeout"}
perpDexs upstream failure502{"error":"upstream unavailable"}

Common Errors#

ErrorCauseSolution
401 UnauthorizedInvalid API keyVerify your API key is correct
403 ForbiddenType denied in server configContact support — this type may be disabled
429 Too Many RequestsRate limit exceededImplement request throttling

Robust Error Handling#

async function safeBatchQuery(users, dex, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await getBatchClearinghouseStates(users, dex);
} catch (error) {
if (error.message.includes('413')) {
// Too many users — split into smaller batches
throw new Error(`Reduce batch size. Limit is ${dex === 'ALL_DEXES' ? 100 : 1000} users.`);
} else if (error.message.includes('429')) {
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
} else if (i === maxRetries - 1) {
throw error;
}
}
}
}

Batch query Hyperliquid account states with Dwellir's HyperCore Info Endpoint. Get your API key →