API servers and how state reaches you
API servers follow a node, keep a local copy of HyperCore state, answer reads from it, and reply to a transaction only once it executes in a committed block.
Every REST or WebSocket call you make goes to an API server. How it answers tells you what a reply, a timeout or a read really means.
Writes are answered after commit
Section titled “Writes are answered after commit”A signed /exchange action goes to the API server, then its node, which gossips it into HyperBFT. The reply comes after commit, so resting or filled describes executed state, not a receipt.
Latency is the hop to the API server, mempool inclusion and commit (figures below). Ordering is far less noisy: in the docs’ experiments, sends under 10 ms apart landed in a predictable order on chain.
What this means for you. A timeout, 5xx or 429 on an action is an unknown outcome, not a failure: check by client order id before resending.
Reads come from the server’s copy
Section titled “Reads come from the server’s copy”/info and WebSocket answer from the API server’s copy, as current as its node’s last update. They return current state (balances, books, positions, open orders) and only bounded history (below); no public stream carries every fill. History lives in node outputs and archives (historical data).
Say your bot polls l2Book. Each call weighs 2 against 1200 per minute per IP, so 600 polls a minute, 10 a second, use the whole budget. An order batch of 80 weighs 1 + floor(80 / 40), which is 3. During congestion a batch’s weight is set by its batch size and a constant per-action weight, so batching still costs less than separate sends.
Use WebSocket for anything you would poll. One measured bot blocked its own order placement because order preparation hit /info first; moving the book to WebSocket cut it to about 0.15 requests per second.
The servers run in Tokyo
Section titled “The servers run in Tokyo”They run on AWS in Tokyo, as established by one production trading setup. The docs’ latency figures assume a co-located client but name no region. Distance to Tokyo is the latency cost you control most directly.
Your own node is faster for reads
Section titled “Your own node is faster for reads”The docs recommend a non-validating node against a reliable peer: its outputs are faster and more granular than the API, enough to build a book locally. Streaming transactions before they are included in client blocks is faster still, but without execution results (running a node, optimising latency).
The numbers
Section titled “The numbers”| Limit, per IP address | Value |
|---|---|
| REST weight | 1200 per minute |
exchange request weight |
1 + floor(batch_length / 40) |
info weight: l2Book, allMids, clearinghouseState, orderStatus, spotClearinghouseState, exchangeStatus |
2 |
info weight: userRole |
60 |
info weight: other documented requests |
20 |
| WebSocket connections | 10 |
| New WebSocket connections | 30 per minute |
| WebSocket subscriptions | 1000 |
| Unique users across user-specific subscriptions | 10 |
| Messages sent over WebSocket | 2000 per minute |
| In-flight WebSocket posts | 100 |
Address-based limits and buying more capacity: rate limits.
| Latency or bound | Value |
|---|---|
| Commit | usually 2 blocks, in pipelined HyperBFT |
| Order, co-located client (docs) | median 0.2 s, 99th percentile 0.9 s |
| Cancel or post-only order (docs) | about 380 ms |
| Tokyo to Ireland hedge (measured) | 350 to 500 ms: about 110 ms network transit plus four serialised round trips |
| Streaming from a node before client-block inclusion | saves 70 to 150 ms |
| Suggested node hardware | at least 32 logical cores, 128 GB RAM, 500 MB/s disk throughput |
userFills, historicalOrders |
at most the 2000 most recent entries; userFillsByTime pages by time, 2000 per response, back to the 10000 most recent fills |
outcomeMeta |
unsettled outcomes only; a settled one drops within about a minute |
Explorer userDetails |
last 300 actions, with an error field, including actions sent from the HyperEVM |
Handling limits and dropped sockets
Section titled “Handling limits and dropped sockets”- A 429 carries no
Retry-Afterheader; back off with jitter. - Per the docs, API servers may drop WebSocket clients without warning. Missed data arrives in the reconnect snapshot; WebSocket posts are not replayed.
- A WebSocket post can fail with “too many pending post requests”.
- An unsupported subscription gets an
errorchannel frame, not silence. ThewebData2subscription is dead (the docs now listwebData3); thewebData2info request still works. A user subscription keyed by an API wallet’s address returns empty: use the master or sub-account address. - Set
TCP_NODELAYon the socket.
The API, not the docs, decides what exists
Section titled “The API, not the docs, decides what exists”A sweep found about 18 exchange actions and 19 info requests working undocumented on mainnet, and some documented ones rejected; the docs have since added cDeposit2, trailingStop and userStarState. The action is parsed before the signature is checked, so a dummy signature separates a wrong shape (HTTP 422 Failed to deserialize) from a valid one (Unable to recover signer, does not exist or Must deposit before performing actions). A 422 can be plain text: read the body as text before parsing JSON.
For subscriptions, posts and heartbeats, see WebSocket. For what distance costs, see Latency, priority and infrastructure.