Products
Datacenter proxies from $19/mo Rotating proxies from $49/mo ISP proxies from $33/mo Dedicated proxies from $3.50/mo UDP proxies from $5/mo Try proxies
Use cases
Data & scraping AI services Social media & messaging E-commerce & finance Media & entertainment Marketing & ads Automation & tools All use cases →
Pricing
Full pricing table All 20 locations Money-back guarantee
Resources
Blog Proxy API MCP server Setup guides FAQ For business About us Affiliate program
English
English Русский
← PapaProxy.net Blog

How the Hyperliquid API weight budget is spent per IP

Hyperliquid’s REST budget is 1,200 weight per minute per IP, and a typical info call costs 20 of it — sixty requests, not twelve hundred. Here’s what each endpoint costs, how the separate wallet-level limit works, and what a real 429 returns.

Limits & performance · API & data August 7, 2026 8 min read Alex Young Alex Young Technical specialist
Key takeawaysThe per-IP budget is 1,200 weight per minute, not 1,200 requests. A typical info call costs 20 weight, so the practical ceiling is about 60 calls a minute.
  • The per-IP budget is 1,200 weight per minute, not 1,200 requests. A typical info call costs 20 weight, so the practical ceiling is about 60 calls a minute.
  • Six read endpoints (l2Book, allMids, clearinghouseState, orderStatus, spotClearinghouseState, exchangeStatus) cost only 2 weight; userRole costs 60; large responses add extra weight on top of the base price.
  • A second, independent limit follows the wallet: cumulative traded volume sets the baseline allowance at 1 action per 1 USDC on top of a 10,000-request starter buffer, and the reserveRequestWeight action buys extra actions outright at 0.0005 USDC each. It counts actions only — info requests are exempt.
  • Neither 200s nor 429s carry any rate-limit headers, and the 429 body is literally null with no Retry-After — we verified this on a live run. The only way to know your remaining budget is to count weight client-side.
  • Batching cuts IP weight dramatically — a 40-order batch costs 2 weight instead of 40 — but the address-based limit still counts it as 40 requests.
  • Extra IP addresses multiply the read budget for parallel workloads; they do nothing for the wallet-level action limit, which follows the address, not the connection.
  • Neither budget is reported back to you mid-flight, so both have to be tracked client-side: weight per egress IP, actions per wallet.

This summary was created with AI.

What a request actually costs

The number everyone quotes — 1,200 per minute per IP — is a weight budget, not a request counter. Every REST call to api.hyperliquid.xyz debits some weight from a shared pool covering both /info and /exchange, and the debit varies by a factor of sixty depending on what you call. Several third-party guides simplify this to “1,200 requests per minute,” and that simplification is exactly how a data collector ends up throttled at one request per second: the weight of an info request defaults to 20, so the documented budget works out to about 60 typical info calls a minute, not 1,200.

The official rate limit documentation defines three price tiers for /info and a formula for /exchange:

Call Weight Calls per minute the budget allows
l2Book, allMids, clearinghouseState, orderStatus, spotClearinghouseState, exchangeStatus 2 600
Any other documented info request (meta, candleSnapshot, userFills, openOrders, …) 20 60
userRole 60 20
Unbatched exchange action (order, cancel, modify) 1 1,200
Batched exchange action with n orders 1 + floor(n/40)
Explorer API request 40 30

Two things in that table catch people. First, trading is cheap and reading is expensive: an unbatched order costs 1 weight while the metadata call to price it costs 20. The model rewards bots that stream market data over WebSocket and touch REST only to act. Second, the weight per minute you actually burn depends on response sizes, not just call counts — several endpoints add surcharges on top of the base price, which is worth a section of its own below.

A concrete budget: polling meta once a second costs 20 × 60 = 1,200 weight — the entire minute’s allowance for one metadata loop. The same poll against allMids costs 120, leaving 90% of the budget free.

Two limits that apply at once

The IP budget is only half of the picture. Hyperliquid’s user limits track your wallet address separately, and the two systems answer different questions: the IP limit protects the API frontend from request floods, while the address limit prices your right to send actions — orders, cancels, modifications — in proportion to how much you actually trade.

The address-based formula: every 1 USDC of cumulative traded volume since the address first appeared earns 1 request, and each address starts with a buffer of 10,000. A bot that places 100-USDC orders needs roughly a 1% fill rate to break even on this budget. Once the allowance runs out, the address is allowed one request every 10 seconds — enough to limp, not to trade. Two safety valves soften the wall: cancels get a higher cumulative allowance of min(limit + 100,000, limit × 2), so you can always pull your open orders, and info requests aren’t counted at all — a rate-limited address can still read its own state freely. Sub-accounts count as separate users with their own buffers.

Traded volume is no longer the only way to raise that ceiling. The reserveRequestWeight action on /exchange reserves additional actions outright at 0.0005 USDC per request, charged to your Perps balance, and its optional destination field lets you pay for another existing L1 address instead of your own. So the current model has two inputs: cumulative volume sets the baseline allowance, and reserved weight extends it on demand — which is how a new strategy buys headroom before it has the trading history to earn it.

Unlike the IP budget, this one is observable. The userRateLimit info request returns the exact state of any address:

Bash
curl -s https://api.hyperliquid.xyz/info \
  -H "Content-Type: application/json" \
  -d '{"type": "userRateLimit", "user": "0x2ba553d9f990a3b66b03b2dc0d030dfc1c061036"}'

A response we pulled while writing this article, for one of the most active addresses on the exchange:

JSON
{
  "cumVlm": "15466177056.6800003052",
  "nRequestsUsed": 2682032,
  "nRequestsCap": 15466187056,
  "nRequestsSurplus": 0
}

nRequestsCap corresponds to the integer cumulative-volume allowance plus the 10,000 starter buffer — the fractional USDC in cumVlm doesn’t buy a fraction of an action. Read the cap as a lifetime ceiling rather than a balance: the two neighboring fields net it against reserved capacity, with nRequestsUsed reported as max(0, used − reserved) and nRequestsSurplus as max(0, reserved − used). For a fresh wallet the same call returns a cap of 10,000 — worth checking before you deploy, not after.

The batching rule ties the two systems together, and it cuts in opposite directions. A batch of 40 orders costs 1 + floor(40/40) = 2 weight against the IP budget — twenty times cheaper than sending them one by one — but the address-based ledger counts it as 40 requests regardless. Batching protects the IP budget; the address budget grows only through traded volume or weight reserved with reserveRequestWeight. The exchange API rate limits, in other words, can’t be gamed by packing — every order is eventually paid for by a fill, by reserved weight, or by the 10,000 buffer draining away.

Endpoints that cost more than you expect

The base info endpoint weight of 20 is only the entry price for some calls. Thirteen history-style endpoints — recentTrades, historicalOrders, userFills, userFillsByTime, fundingHistory, userFunding, nonUserFundingUpdates, twapHistory, userTwapSliceFills, userTwapSliceFillsByTime, delegatorHistory, delegatorRewards, validatorStats — add 1 extra weight per 20 items in the response. A response carrying 500 items therefore costs 20 base + 25 surcharge = 45 weight. Sizes run well past that: the current userFills card allows up to 2,000 recent fills, and userFillsByTime returns at most 2,000 per response out of the 10,000 most recent — while the general pagination note on the rate-limits page still says time-range responses return at most 500 elements. Those two statements sit in the documentation side by side, so budget from the response you actually receive rather than an assumed page size; a backfill loop walking history page by page can burn weight several times faster than the base price suggests.

candleSnapshot has its own gentler surcharge — 1 extra weight per 60 candles — and its own hard boundary: only the most recent 5,000 candles per coin and interval are available, full stop. Pulling all of them in one call costs on the order of 100 weight, which is fine as a one-off warm-up. What the endpoint can’t do at any price is reach deeper history — there is no startTime far enough in the past, so a research dataset has to be accumulated by your own collector while the data is current, or come from somewhere other than the API.

Explorer API calls cost 40 each, blockList adds a further 1 per block, and blocks that haven’t been queried recently may be weighted more heavily still — for bulk chain history the documentation points at the public S3 bucket instead of the API. And one oddity worth knowing: userRole, a trivial-looking lookup of whether an address is a user, vault, or sub-account, costs 60 weight — three metadata calls’ worth. Cache it.

What a 429 actually looks like: we checked

Exchange docs rarely describe their own throttle responses, and third-party writeups fill the gap with inventions — we’ve seen guides claim Hyperliquid returns a Retry-After header and a retry_after JSON field, and even that it suspends “API keys” — Hyperliquid doesn’t use conventional API-key authentication at all, since actions are signed by the wallet itself or by an approved API wallet (also called an agent wallet). So on August 7, 2026, we probed the mainnet /info endpoint from a single machine with the weight-20 meta request at three pacing profiles and recorded what actually came back:

Pace Nominal weight/min Result
0.8–1 request/s 960–1,200 — at or just under the wall 194 requests across two runs, not a single 429
~2.8 requests/s ~3,360 276 requests passed, first 429 at second 98; a single retry 6 seconds later returned 200
80 requests in one burst, 8 parallel connections TCP connection resets before any HTTP status; 3 of 80 got through

The scope of that run is narrow on purpose: one machine, one address, one endpoint, on a single date. Each profile stopped at its first rejection instead of escalating further, so the numbers describe what the API did in that window rather than a guaranteed enforcement curve. There’s no reason to reproduce the overrun against production either — the useful half of the result is the shape of the 429, and that’s visible from a single rejected request.

A broader follow-up in our Hyperliquid leaderboard and wallet-position experiment tested clearinghouseState, allMids, and meta across datacenter and ISP addresses. The first 429 appeared after 1.8–2.3× the documented weight budget, but the sustained planning rate was 574 clearinghouseState calls per minute per datacenter address — close to the documented 600. That confirms the practical rule here: plan from the published budget and treat any extra headroom as burst tolerance, not dependable capacity.

Three practical findings. First, the anatomy of the 429 itself: the body is the four bytes null, and there is no Retry-After, no rate-limit headers, nothing to parse — on this exchange, unlike Binance with its X-MBX-USED-WEIGHT counters, the server never tells you how much budget you have left, before or after the wall. The only gauge you’ll ever have is the one you build client-side. Second, enforcement is not a guillotine at 1,201: the overrun ran for a minute and a half before the first rejection, and a single retry six seconds later succeeded. That’s one observation, not a recovery-time distribution — we didn’t measure one. Treat the slack as unguaranteed either way: budget to the documented 1,200 and let anything softer be a pleasant surprise. Third, sharp connection bursts fail below the HTTP layer entirely. Most failed attempts in the burst run ended with a connection reset before any HTTP response arrived, and a client-side error can’t identify which component issued the reset — the exchange edge, the CDN in front of it, or something along the network path. The practical consequence is the same regardless: your client raises a socket error rather than an HTTP status, and retry logic keyed on status_code == 429 never fires. Our test client also opened a fresh TCP connection per request, and occasional resets appeared even at one request per second — handle both failure shapes, and reuse connections.

Since the server gives you no counters, the counting looks like this — a budgeter for one process and one egress IP, demonstration-grade:

Python
import time, requests

API = "https://api.hyperliquid.xyz/info"
BUDGET = 1_200        # documented weight per minute per IP
SAFETY = 0.9          # spend at most 90% — there are no headers to correct against

session = requests.Session()   # one connection, reused: bursts of new ones get reset
spent = []                     # (monotonic time, weight) of calls in the last 60 seconds

def acquire(weight):
    now = time.monotonic()     # immune to clock adjustments mid-window
    while spent and now - spent[0][0] > 60:
        spent.pop(0)
    if sum(w for _, w in spent) + weight > BUDGET * SAFETY:
        return False
    spent.append((now, weight))
    return True

def info(payload, weight):
    delay = 1
    while True:
        while not acquire(weight):
            time.sleep(0.25)
        try:
            r = session.post(API, json=payload, timeout=10)
        except (requests.ConnectionError, requests.Timeout):   # reset or stall, no status
            time.sleep(delay); delay = min(delay * 2, 30)
            continue
        if r.status_code == 429:           # no Retry-After — back off blind
            time.sleep(delay); delay = min(delay * 2, 30)
            continue
        r.raise_for_status()
        return r.json()

What this deliberately leaves out: it assumes a single egress IP. The budget is granted per address, so a client routed through several proxies needs one counter per egress, keyed by proxy — pointing ten proxies at this one global list would model a tenth of the real capacity and throttle you for no reason. It also trusts the caller to pass the true weight (including response-size surcharges, which you only know after the response — count them retroactively against the window), it keeps state in process memory so a restart forgets the last minute of spending, and it coordinates nothing — multiple workers behind one IP need a shared counter in Redis or similar, the same pattern we walk through in the Binance article. It sends no orders and changes no exchange state, so the worst case of a lost response is a wasted retry, not a duplicated trade.

Staying under the budget

Hyperliquid leaves plenty of official room to move load off REST. WebSocket carries market data outside the REST budget entirely — one l2Book subscription replaces six hundred weight-2 polls a minute — within its own per-IP limits: 10 connections, 30 new connections a minute, 1,000 subscriptions, 2,000 messages sent to Hyperliquid per minute across all connections, 100 simultaneous inflight post messages, and user-specific subscriptions covering at most 10 distinct users. Batching compresses action costs on the IP side, response caching kills repeat meta calls, and bulk chain history belongs in the S3 bucket rather than the explorer API. A bot that streams reads, batches writes, and caches metadata rarely sees the 1,200 wall at all.

What’s left after those optimizations is workloads that are genuinely parallel: an analytics service polling clearinghouseState for hundreds of tracked wallets, a market-data collector snapshotting order books across every listed coin, a fleet of independent bots that shouldn’t share one address’s budget or one point of failure. The IP budget doesn’t stretch — but it multiplies, because it’s granted per IP address. The honest boundary here is the address-based action limit: it follows the wallet, and no number of IPs raises it — that ceiling moves only with traded volume or weight reserved through reserveRequestWeight. What extra addresses do multiply is everything measured per IP — read weight, WebSocket connections, subscription slots.

That’s the workload our crypto proxies are built for: dedicated IPv4 addresses that stay static for the plan term, each carrying its own 1,200-weight budget and its own WebSocket allowance, with HTTP, HTTPS, SOCKS4, and SOCKS5 on every address and access by IP whitelisting. One address per collector keeps a burst in one worker from throttling the rest — and keeps a TCP reset from taking down anything but the process that caused it.