Hyperliquid exposes two main HTTP endpoints (Info and Exchange) plus a WebSocket feed. You can call them directly, but signing, nonces, asset IDs and reconnect handling add up quickly. This quickstart walks through @siebly/hyperliquid-api, an MIT-licensed SDK for Node.js, JavaScript and TypeScript, from install to a live WebSocket subscription.
Everything below uses classes and methods exported by the package. The full reference lives in the Hyperliquid JavaScript SDK docs.
What you get
- One
RestClientfor public market data, account information, orders, transfers and more. - A
WebsocketClientwith heartbeats, automatic reconnect and resubscribe. - A
WebsocketAPIClientthat mirrors the REST methods over Hyperliquid's WebSocket POST protocol. - TypeScript declarations for requests and responses, with dual ESM and CommonJS builds.
- Testnet support through a single
testnet: trueoption.
Install
The package supports Node.js 22 or newer.
npm install @siebly/hyperliquid-api TypeScript is optional, but the type declarations make the request shapes much easier to discover in your editor.
Your first public REST call
Public Info methods need no credentials. Start by checking the exchange status, then pull mid prices and an order book:
import { RestClient } from '@siebly/hyperliquid-api'; const client = new RestClient(); async function main() { const status = await client.getExchangeStatus(); console.log('Exchange status:', status); // AllMidsResponse is Record<string, string>: coin to mid price const mids = await client.getAllMids(); console.log('Coins with a mid price:', Object.keys(mids).length); console.log('BTC mid:', mids['BTC'] ?? 'not listed'); const book = await client.getOrderBook({ coin: 'BTC', nSigFigs: 5, }); if (book) { console.log('Best bid level:', book.levels[0][0]); } } main().catch((error) => { console.error('Request failed:', error); }); The SDK uses readable get... names rather than Hyperliquid's internal request type names, so getAllMids() maps to the allMids Info request and getOrderBook() to l2Book.
You can also read any public account by address, without a key:
const user = '0x1234567890123456789012345678901234567890'; const perpSummary = await client.getPerpAccountSummary({ user }); const spotBalances = await client.getSpotBalances({ user }); Authenticated client setup
Signed methods take a private key, and that key belongs on a trusted backend only. Read it from an environment variable rather than hard-coding it:
import { RestClient } from '@siebly/hyperliquid-api'; const privateKey = process.env.HYPERLIQUID_PRIVATE_KEY; if (!privateKey) { throw new Error('Set HYPERLIQUID_PRIVATE_KEY before starting.'); } const client = new RestClient({ privateKey, testnet: true, }); const balances = await client.getBalances(); console.log('Account:', balances.user); console.log('Spot:', balances.spot.balances); console.log('Perpetuals:', balances.perp.assetPositions); const openOrders = await client.getOpenOrders(); console.log('Open orders:', openOrders.length); A few notes:
- Use testnet first.
testnet: truepoints the client at Hyperliquid's testnet API, so you can exercise signing and order flows without touching a real account. - Keep keys server-side. Never put a private key in frontend code, browser storage or a public environment variable. Public REST calls and public subscriptions are browser-safe; signed calls are not.
- Custom signers. If you would rather not hand the SDK a raw key, the constructor also accepts a
signerwith a portablesignTypedDataimplementation.
Once that works, the client exposes helpers for common order workflows. This places a post-only limit order on testnet:
const order = await client.submitLimitOrder({ symbol: 'BTC', side: 'buy', size: '0.001', price: '50000', timeInForce: 'GTC', }); if (order.status === 'ok') { console.log(order.response.data); } Exchange methods return an ExchangeResponse wrapper, so check status === 'ok' before reading response.data. For the full order surface, including submitOrder() with raw Hyperliquid order fields and submitMarketOrder(), see the Hyperliquid API JavaScript tutorial.
The README also documents how the SDK handles Hyperliquid referral and builder codes on orders; read that section before running anything on mainnet.
Subscribing to WebSocket streams
WebsocketClient opens connections when they are first needed, deduplicates matching subscriptions, sends heartbeats, and reconnects then resubscribes after a drop. You register listeners once and subscribe to topics separately:
import { WebsocketClient } from '@siebly/hyperliquid-api'; const ws = new WebsocketClient({ testnet: true }); ws.on('message', (event) => { if (event.channel === 'l2Book') { console.log(event.wsKey, event.data.coin, event.data.levels); } else if (event.channel === 'trades') { console.log(event.wsKey, event.data); } }); ws.on('response', (event) => { console.log('Acknowledgement:', event.wsKey, event.channel, event.data); }); ws.on('reconnected', ({ wsKey }) => { console.log('Reconnected:', wsKey); }); ws.on('exception', ({ wsKey, event, data }) => { console.error('WebSocket exception:', wsKey, event ?? data); }); const book = { type: 'l2Book', coin: 'BTC', nSigFigs: 5, } as const; const trades = { type: 'trades', coin: 'ETH' } as const; await ws.subscribe([book, trades]); // Later, when the feeds are no longer needed: // await ws.unsubscribe([book, trades]); // ws.closeAll(); subscribe() resolves once the socket is open and the request has been sent. The server's acknowledgement arrives on the response event, and data arrives on message with the upstream envelope intact plus a wsKey.
Coin identifiers such as BTC, @107 or PURR/USDC pass straight through. If you want to resolve a readable alias first, there is a helper:
const coin = await ws.nameToCoin('HYPE/USDC'); await ws.subscribe({ type: 'trades', coin }); Reconnect timing, ping interval and pong deadline are all configurable through the constructor options if the defaults do not suit your deployment.
Request and response over WebSockets
If you want the REST-style methods but over a persistent socket, WebsocketAPIClient provides the same Info and Exchange methods as RestClient:
import { WebsocketAPIClient } from '@siebly/hyperliquid-api'; const client = new WebsocketAPIClient({ testnet: true }); const mids = await client.getAllMids(); console.log(mids); client.close(); Debugging tips
- Pass a custom logger as the second argument to
WebsocketClientto see pings, subscriptions and messages at trace level. -
RestClientaccepts Axios-compatible network options as its second argument, which lets you route requests through a local debugging proxy. Avoid logging signed/exchangebodies. - If Hyperliquid ships a new operation before the SDK has a typed wrapper,
submitRawInfoRequest()keeps it usable in the meantime.
Next steps
- Read the Hyperliquid JavaScript SDK docs for the overview and feature list.
- Work through the Hyperliquid API JavaScript tutorial for Node.js, which covers perpetual and Spot orders, account streams, the WebSocket API, testnet and proxies in more depth.
- Follow the Hyperliquid SDK quickstart guide on GitHub for complete end-to-end workflows.
- Check Hyperliquid SDK release notes for recent changes.
- Browse the source and examples in the sieblyio/hyperliquid-api repository, or install from npm.
Questions or bug reports are welcome on the GitHub issues tab.
