Skip to content
BuildBuild on HyperCore16 pages
Architecture: info, exchange, WebSocketFoundationHyperliquid's API has three surfaces: an unsigned read endpoint, a signed write endpoint, and a WebSocket that streams data and can carry both.Your first requestFoundationReading Hyperliquid needs no key, no account and no risk: three unsigned POST requests return the list of markets, an order book and any address's positions.Asset ids and namingPractitionerOrders name a market by an integer asset id and info requests by a coin string, and perps, spot, HIP-3 and outcomes each derive both by a different rule.Precision: tick size, lot size, significant figuresPractitionerA HyperCore price has at most 5 significant figures and a decimal cap set by szDecimals, a size at most szDecimals decimals, and outcomes use a 0.00001 grid.Signing from first principlesExpertL1 actions sign a keccak hash of their msgpack bytes, user-signed actions sign readable EIP-712 data, and one wrong byte in either recovers a stranger's address.Nonces, expiry and API walletsPractitionerHyperCore keeps each signer's 100 highest nonces and accepts a new one only if unused, above the smallest, and within 2 days before and 1 day after block time.Orders: place, modify, cancel, batch, dead man's switchPractitionerAn order is a signed action carrying a batch of compact orders; modify, cancel, TWAP and the dead man's switch are separate actions, each with its own response.Transfers and withdrawalsPractitionerEvery HyperCore transfer is a signed action: sends and withdrawals need the account's own key, and an API wallet's transfer actions keep value inside the account.Multi-sig actionsExpertA multi-sig action carries enough authorised users' signatures over one nonce and one named leader, in an envelope only the leader signs and submits.WebSocket: subscriptions, post requests, heartbeatsPractitionerOne WebSocket streams book, trade and account updates as blocks execute and carries signed actions, but drops without warning and forgets every subscription.Rate limits and user limitsPractitionerHyperliquid meters each IP by request weight, 1200 per minute, and each address by actions: 10,000 plus one per USDC traded.Priority fees and the activation feeExpertHyperliquid sells latency in two burned auctions, read priority per IP and write priority per order, and charges 1 quote token to activate a new account.Error responsesPractitionerHyperliquid reports errors at four layers, from HTTP status to a string inside a successful response, and several name a cause other than the real one.Debugging signatures and wire shapesExpertA signature over wrong bytes still verifies, so HyperCore recovers a stranger's address and says it does not exist; the fix is almost always the encoding.Optimising latencyExpertMost of an order's round trip is consensus; code wins by streaming reads, cutting serial round trips, using the fast order class and never stalling orders.Data: historical, node and explorerPractitionerThe API keeps only recent history; a full record needs pagination, archived node data or your own node, and each trade counted once by its trade id.
BuildBuild on the HyperEVM9 pages
What the HyperEVM is, and is notFoundationThe HyperEVM is Hyperliquid's smart contract environment: it reads HyperCore state and queues HyperCore actions, but never executes them atomically.Blocks, gas and RPCPractitionerThe HyperEVM produces small blocks every second and big blocks every minute, prices gas with EIP-1559 in HYPE, and serves a JSON-RPC with no historical state.Moving assets between HyperCore and the HyperEVMPractitionerLinked tokens cross between HyperCore and the HyperEVM via per-token system addresses, with a decimal offset and a 200k-gas fee when leaving HyperCore.Linking a tokenExpertLinking binds a HyperCore token to one ERC20 through the spot deployer's request and the contract deployer's finalisation; the protocol checks almost nothing else.Reading HyperCore: precompilesExpertRead precompiles are 21 fixed addresses, 0x800 to 0x814, that return HyperCore state as of the EVM block's construction, and only at the latest block.Writing to HyperCore: CoreWriterExpertCoreWriter turns a contract call into a HyperCore action for the caller's own account, run after the EVM block, with no result returned and no revert on refusal.Execution order and timingExpertEach L1 block runs the EVM block, then EVM to HyperCore transfers, then CoreWriter actions; on mainnet most actions land within half a second, vault transfers in about 4 s.PatternsExpertA contract that touches HyperCore stays solvent by recording an intent, sending the action, and settling only on HyperCore state that visibly moved.Footguns, measuredExpertTwelve ways a HyperEVM contract loses money or silently does nothing when it touches HyperCore, each with the on-chain evidence and the fix.

WebSocket: subscriptions, post requests, heartbeats

Practitioner

One WebSocket streams book, trade and account updates as blocks execute and carries signed actions, but drops without warning and forgets every subscription.

You open one connection to wss://api.hyperliquid.xyz/ws and exchange JSON messages. A subscription pushes updates as blocks execute. A poll sees only the state when it lands, and spends IP weight that order placement also needs (one bot’s measured fix).

Say you follow ETH’s book and your own fills, 2 of the 1000 subscriptions an IP may hold. After a drop both are gone: you reconnect, subscribe again, and the fresh userFills snapshot covers the gap.

Your client API server subscribe userFills subscriptionResponse userFills, isSnapshot: true userFills, streaming ping pong post id 7 (order) Server drops the socket. Post 7 is never answered. reconnect, subscribe userFills again new snapshot covers the gap
Resubscribing after a drop returns a fresh snapshot. A post in flight is never answered and must be reconciled.
{"method": "subscribe", "subscription": {"type": "l2Book", "coin": "ETH"}}

The server acknowledges with {"channel": "subscriptionResponse", "data": {...}} echoing the subscription, then sends frames on a channel named after the type ("l2Book"); userEvents arrives on "user". To stop, send "method": "unsubscribe" with an identical subscription object; other subscriptions are unaffected.

Time-series feeds (userFills, userFundings, userTwapSliceFills, userTwapHistory) open with a snapshot of past data tagged isSnapshot: true, then isSnapshot: false. fastAssetCtxs also opens with a snapshot, then sends only changed coins.

Type Parameters What arrives
l2Book coin, optional nSigFigs, mantissa, fast full book snapshot, levels: [bids, asks], each level {px, sz, n}
bbo coin best bid and offer, sent only when it changes on a block
trades coin trades with users: [buyer, seller] and tid
allMids optional dex mid prices; spot mids only with the first perp dex
candle coin, interval candles; intervals 1m to 1M
activeAssetCtx coin mark, mid, volume; funding, open interest and oracle for perps
orderUpdates user order objects with a status string
userFills user, optional aggregateByTime snapshot, then new fills
userEvents user fills, funding, liquidations, non-user cancels, on channel user
userNonFundingLedgerUpdates user deposits, withdrawals, transfers, vault flows
clearinghouseState, openOrders user, dex one perp dex’s account state or open orders
spotState user, optional isPortfolioMargin spot balances
fastAssetCtxs none base64 raw-deflate JSON of mark and mid prices

Further types in the docs: notification, webData3, twapStates, activeAssetData (perps only), userFundings, userTwapSliceFills, userTwapHistory, allDexsClearinghouseState, allDexsAssetCtxs, outcomeMetaUpdates. Use the account’s own address for user feeds: an API wallet has no fills or orders of its own.

l2Book frames are not diffs. Each is pushed on a block at least 0.5 after the previous push (the docs omit the unit; seconds by context). Aggregation and depth options are in the numbers.

Any info request or signed action can go over the socket, wrapping the usual HTTP body:

{
"method": "post",
"id": 256,
"request": {
"type": "action",
"payload": {
"action": {"type": "order", "orders": [{"a": 4, "b": true, "p": "1100", "s": "0.2", "r": false, "t": {"limit": {"tif": "Gtc"}}}], "grouping": "na"},
"nonce": 1713825891591,
"signature": {"r": "0x...", "s": "0x...", "v": 27}
}
}
}

The reply arrives on channel post with your id; the HTTP response body is in data.response.payload:

{
"channel": "post",
"data": {
"id": 256,
"response": {
"type": "action",
"payload": {"status": "ok", "response": {"type": "order", "data": {"statuses": [{"resting": {"oid": 88383}}]}}}
}
}
}
  • Info requests: request.type is "info" and the payload is the info body.
  • On failure, response.type is "error" and the payload is a string mirroring the HTTP status and description.
  • method and id are mandatory; use a fresh id per post to match replies.
  • Explorer requests are not supported.

Send {"method": "ping"} and the server replies {"channel": "pong"}. One production client pings every 30 seconds.

A dropped socket forgets every subscription

Section titled “A dropped socket forgets every subscription”

The docs warn that API servers disconnect clients periodically and without announcement. Reconnect with backoff and resend every subscription. Feeds without a snapshot need the matching info request to fill the gap.

Posts are not replayed: an in-flight action may or may not have executed, so reconcile it by cloid with orderStatus or openOrders before resending (orders).

Limit (per IP) Value
Connections 10
New connections 30 per minute
Subscriptions 1000
Unique users across user-specific subscriptions 10
Messages sent to the server 2000 per minute, across all connections
Post requests in flight 100, across all connections
Idle timeout 60 s without a message
l2Book levels 20 per side, or 5 with fast
l2Book nSigFigs (significant figures per level) 2, 3, 4, 5, or null for full precision
l2Book mantissa 1, 2 or 5, only with nSigFigs: 5
Candle intervals 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1M
  • One connection per network, with reference-counted subscriptions: components share a feed and the unsubscribe goes out when the last one leaves.
  • Key a registry of live subscriptions by their exact JSON: replay it on reconnect, echo it to unsubscribe.
  • Track pending post ids with a timeout and keep them below 100. One observed failure is too many pending post requests id=N.
  • Following more than 10 users per IP needs polling, or a node’s own output (data).
  • Deduplicate fills on tid, since every resubscribe replays a snapshot and hash is shared by the partial fills of one transaction. For a venue-wide unique trade id the docs use (block_time, coin, tid), because tid is a 50-bit hash of the buyer’s and seller’s order ids.
  • activeAssetCtx on a spot or outcome coin replies on channel activeSpotAssetCtx, with circulatingSupply instead of funding and open interest. A handler keyed only on activeAssetCtx misses it.
  • A dead subscription type returns a frame on channel error, not silence. webData2 subscriptions are dead (the info request still works); the docs’ example still shows a webData subscription.
  • outcomeMetaUpdates frames are arrays; the docs type them as a one-element tuple.
  • fastAssetCtxs is raw DEFLATE with no zlib or gzip header: standard zlib decoding fails, use a raw inflate.
  • Outcome books report a 0.5 mid when nobody has quoted.

For the two HTTP endpoints beside the socket, see Architecture. For its caps next to REST’s, see Rate limits.