Unofficial Hyperliquid API SDK for all major JS runtimes, written in TypeScript. Fork with Node.js 20.18.0+ compatibility.
npm install @deeeed/hyperliquid-node20> ๐ด Fork Notice: This is a fork of the excellent @nktkas/hyperliquid package by nktkas, modified to support Node.js 20.18.0+. All credit for the original implementation goes to the original author.
>
> Original Package: @nktkas/hyperliquid
> This Fork: @deeeed/hyperliquid-node20
> Repository: github.com/abretonc7s/hyperliquid
>
> Why this fork? The original package requires Node.js โฅ24.0.0 due to newer JavaScript features. This fork adds polyfills to support Node.js โฅ20.18.0 while maintaining 100% API compatibility.
>
> ๐ See FORK_CHANGES.md for detailed information about the modifications made.


Unofficial Hyperliquid API SDK for all major JS
runtimes, written in TypeScript and provided with tests.
- ๐๏ธ Typed: Source code is 100% TypeScript.
- ๐งช Tested: Good code coverage and type-safe API responses.
- ๐ฆ Minimal dependencies: A few small trusted dependencies.
- ๐ Cross-Environment Support: Compatible with all major JS runtimes.
- ๐ง Integratable: Easy to use with viem,
ethers and other wallet libraries.
- ๐ Documented: JSDoc annotations with usage examples in source code.
> [!NOTE]
> While this library is in TypeScript, it can also be used in JavaScript and supports ESM/CommonJS.
``
npm i @deeeed/hyperliquid-node20
pnpm add @deeeed/hyperliquid-node20
yarn add @deeeed/hyperliquid-node20
`
> Migration from original: Simply replace @nktkas/hyperliquid with @deeeed/hyperliquid-node20 in your imports. All APIs are identical.
``
deno add jsr:@deeeed/hyperliquid-node20
`html`
For React Native, you need to import polyfills before importing the SDK:
`js
// React Native 0.76.3 / Expo v52
// Issues:
// - signing: does not support private keys directly, use viem or ethers
import { Event, EventTarget } from "event-target-shim";
if (!globalThis.EventTarget || !globalThis.Event) {
globalThis.EventTarget = EventTarget;
globalThis.Event = Event;
}
if (!globalThis.CustomEvent) {
globalThis.CustomEvent = function (type, params) {
params = params || {};
const event = new Event(type, params);
event.detail = params.detail || null;
return event;
};
}
if (!AbortSignal.timeout) {
AbortSignal.timeout = function (delay) {
const controller = new AbortController();
setTimeout(() => controller.abort(), delay);
return controller.signal;
};
}
if (!Promise.withResolvers) {
Promise.withResolvers = function () {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
}
`
#### Info endpoint
`ts
import * as hl from "@deeeed/hyperliquid-node20";
const transport = new hl.HttpTransport();
const infoClient = new hl.InfoClient({ transport });
const openOrders = await infoClient.openOrders({ user: "0x..." });
`
#### Exchange endpoint
`ts
import * as hl from "@deeeed/hyperliquid-node20";
const privateKey = "0x..."; // or viem, ethers
const transport = new hl.HttpTransport();
const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
const result = await exchClient.order({
orders: [{
a: 0,
b: true,
p: "30000",
s: "0.1",
r: false,
t: {
limit: {
tif: "Gtc",
},
},
}],
grouping: "na",
});
`
#### Subscription
`ts
import * as hl from "@deeeed/hyperliquid-node20";
const transport = new hl.WebSocketTransport();
const subsClient = new hl.SubscriptionClient({ transport });
const sub = await subsClient.allMids((event) => {
console.log(event);
});
await sub.unsubscribe(); // unsubscribe from the event
`
#### Multi-Sign
`ts
import * as hl from "@deeeed/hyperliquid-node20";
const multiSignAddress = "0x...";
const signers = [
"0x...", // Private key; or any other wallet libraries
] as const;
const transport = new hl.HttpTransport();
const multiSignClient = new hl.MultiSignClient({ transport, multiSignAddress, signers }); // extends ExchangeClient
const data = await multiSignClient.approveAgent({ // same API as ExchangeClient`
agentAddress: "0x...",
agentName: "agentName",
});
First, choose and configure your transport layer (more details in the API Reference):
`ts
import * as hl from "@nktkas/hyperliquid";
// 1. HTTP Transport: suitable for one-time requests or serverless environments
const httpTransport = new hl.HttpTransport(); // Accepts optional parameters (e.g. isTestnet, timeout, etc.)
// 2. WebSocket Transport: has better network latency than HTTP transport
const wsTransport = new hl.WebSocketTransport(); // Accepts optional parameters (e.g. url, timeout, reconnect, etc.)
`
Next, initialize a client with the transport layer (more details in the API Reference):
#### Create InfoClient
`ts
import * as hl from "@nktkas/hyperliquid";
const transport = new hl.HttpTransport(); // or WebSocketTransport`
const infoClient = new hl.InfoClient({ transport });
#### Create ExchangeClient
`ts
import * as hl from "@nktkas/hyperliquid";
import { createWalletClient, custom } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { ethers } from "ethers";
const transport = new hl.HttpTransport(); // or WebSocketTransport
// 1. Using private key directly
const privateKey = "0x...";
const exchClient_privateKey = new hl.ExchangeClient({ wallet: privateKey, transport });
// 2. Using Viem
const viemAccount = privateKeyToAccount("0x...");
const exchClient_viem = new hl.ExchangeClient({ wallet: viemAccount, transport });
// 3. Using Ethers (or Ethers V5)
const ethersWallet = new ethers.Wallet("0x...");
const exchClient_ethers = new hl.ExchangeClient({ wallet: ethersWallet, transport });
// 4. Using external wallet (e.g. MetaMask) via Viem
const [account] = await window.ethereum.request({ method: "eth_requestAccounts" });
const externalWallet = createWalletClient({ account, transport: custom(window.ethereum) });
const exchClient_viemMetamask = new hl.ExchangeClient({ wallet: externalWallet, transport });
// 5. Using external wallet (e.g. MetaMask) via window.ethereum`
const exchClient_windowMetamask = new hl.ExchangeClient({ wallet: window.ethereum, transport });
#### Create SubscriptionClient
`ts
import * as hl from "@nktkas/hyperliquid";
const transport = new hl.WebSocketTransport(); // only WebSocketTransport`
const subsClient = new hl.SubscriptionClient({ transport });
#### Create MultiSignClient
`ts
import * as hl from "@nktkas/hyperliquid";
import { privateKeyToAccount } from "viem/accounts";
import { ethers } from "ethers";
const multiSignAddress = "0x...";
const signers = [
privateKeyToAccount("0x..."), // first is leader for multi-sign transaction, must contain own address
new ethers.Wallet("0x..."),
{ // can be a custom async wallet
async signTypedData(params: {
domain: {
name: string;
version: string;
chainId: number;
verifyingContract: Hex;
};
types: {
[key: string]: {
name: string;
type: string;
}[];
};
primaryType: string;
message: Record
}): Promise
// Custom signer logic
return "0x..."; // return hex signature
},
},
"0x...", // private key directly
];
const transport = new hl.HttpTransport();
const multiSignClient = new hl.MultiSignClient({ transport, multiSignAddress, signers }); // extends ExchangeClient`
Finally, use client methods to interact with the Hyperliquid API (more details in the API Reference):
#### Example of using an InfoClient
`ts
import * as hl from "@nktkas/hyperliquid";
const transport = new hl.HttpTransport();
const infoClient = new hl.InfoClient({ transport });
// L2 Book
const l2Book = await infoClient.l2Book({ coin: "BTC" });
// Account clearinghouse state
const clearinghouseState = await infoClient.clearinghouseState({ user: "0x..." });
// Open orders
const openOrders = await infoClient.openOrders({ user: "0x..." });
`
#### Example of using an ExchangeClient
`ts
import * as hl from "@nktkas/hyperliquid";
const privateKey = "0x..."; // or viem, ethers
const transport = new hl.HttpTransport();
const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
// Place an orders
const result = await exchClient.order({
orders: [{
a: 0,
b: true,
p: "30000",
s: "0.1",
r: false,
t: {
limit: {
tif: "Gtc",
},
},
}],
grouping: "na",
});
// Approve an agent
const result = await exchClient.approveAgent({
agentAddress: "0x...",
agentName: "agentName",
});
// Withdraw funds
const result = await exchClient.withdraw3({
destination: account.address,
amount: "100",
});
`
#### Example of using a SubscriptionClient
`ts
import * as hl from "@nktkas/hyperliquid";
const transport = new hl.WebSocketTransport();
const subsClient = new hl.SubscriptionClient({ transport });
// L2 Book updates
await subsClient.l2Book({ coin: "BTC" }, (data) => {
console.log(data);
});
// User fills
await subsClient.userFills({ user: "0x..." }, (data) => {
console.log(data);
});
// Candle updates
const sub = await subsClient.candle({ coin: "BTC", interval: "1h" }, (data) => {
console.log(data);
});
`
#### Example of using a MultiSignClient
`ts
import * as hl from "@nktkas/hyperliquid";
const multiSignAddress = "0x...";
const signers = [
"0x...", // Private keys
] as const;
const transport = new hl.HttpTransport();
const multiSignClient = new hl.MultiSignClient({ transport, multiSignAddress, signers });
// Interaction is the same as with ExchangeClient
// Place an orders
const result = await multiSignClient.order({
orders: [{
a: 0,
b: true,
p: "30000",
s: "0.1",
r: false,
t: {
limit: {
tif: "Gtc",
},
},
}],
grouping: "na",
});
// Approve an agent
const result = await multiSignClient.approveAgent({
agentAddress: "0x...",
agentName: "agentName",
});
// Withdraw funds
const result = await multiSignClient.withdraw3({
destination: account.address,
amount: "100",
});
`
A client is an interface through which you can interact with the Hyperliquid API.
The client is responsible for formatting an action, creating a signature correctly, sending a request, and validating a
response.
#### InfoClient
`ts
class InfoClient {
constructor(args: {
transport: HttpTransport | WebSocketTransport;
});
// Market
allMids(): Promise
candleSnapshot(args: CandleSnapshotParameters): Promise
fundingHistory(args: FundingHistoryParameters): Promise
l2Book(args: L2BookParameters): Promise
liquidatable(): Promise
marginTable(args: MarginTableParameters): Promise
maxMarketOrderNtls(): Promise<[number, string][]>;
meta(): Promise
metaAndAssetCtxs(): Promise
perpDeployAuctionStatus(): Promise
perpDexs(): Promise<(PerpDex | null)[]>;
perpsAtOpenInterestCap(): Promise
predictedFundings(): Promise
spotDeployState(args: SpotDeployStateParameters): Promise
spotMeta(): Promise
spotMetaAndAssetCtxs(): Promise
tokenDetails(args: TokenDetailsParameters): Promise
// Account
clearinghouseState(args: ClearinghouseStateParameters): Promise
extraAgents(args: ExtraAgentsParameters): Promise
isVip(args: IsVipParameters): Promise
legalCheck(args: LegalCheckParameters): Promise
maxBuilderFee(args: MaxBuilderFeeParameters): Promise
portfolio(args: PortfolioParameters): Promise
preTransferCheck(args: PreTransferCheckParameters): Promise
referral(args: ReferralParameters): Promise
spotClearinghouseState(args: SpotClearinghouseStateParameters): Promise
subAccounts(args: SubAccountsParameters): Promise
userFees(args: UserFeesParameters): Promise
userFunding(args: UserFundingParameters): Promise
userNonFundingLedgerUpdates(args: UserNonFundingLedgerUpdatesParameters): Promise
userRateLimit(args: UserRateLimitParameters): Promise
userRole(args: UserRoleParameters): Promise
userToMultiSigSigners(args: UserToMultiSigSignersParameters): Promise
// Order
frontendOpenOrders(args: FrontendOpenOrdersParameters): Promise
historicalOrders(args: HistoricalOrdersParameters): Promise
openOrders(args: OpenOrdersParameters): Promise
orderStatus(args: OrderStatusParameters): Promise
twapHistory(args: TwapHistoryParameters): Promise
userFills(args: UserFillsParameters): Promise
userFillsByTime(args: UserFillsByTimeParameters): Promise
userTwapSliceFills(args: UserTwapSliceFillsParameters): Promise
userTwapSliceFillsByTime(args: UserTwapSliceFillsByTimeParameters): Promise
// Validator
delegations(args: DelegationsParameters): Promise
delegatorHistory(args: DelegatorHistoryParameters): Promise
delegatorRewards(args: DelegatorRewardsParameters): Promise
delegatorSummary(args: DelegatorSummaryParameters): Promise
validatorL1Votes(): Promise
validatorSummaries(): Promise
// Vault
leadingVaults(args: LeadingVaultsParameters): Promise
userVaultEquities(args: UserVaultEquitiesParameters): Promise
vaultDetails(args: VaultDetailsParameters): Promise
vaultSummaries(): Promise
// Server
exchangeStatus(): Promise
// Explorer (RPC endpoint)
blockDetails(args: BlockDetailsParameters): Promise
txDetails(args: TxDetailsParameters): Promise
userDetails(args: UserDetailsParameters): Promise
}
`
#### ExchangeClient
`tsisTestnet
class ExchangeClient {
constructor(args: {
transport: HttpTransport | WebSocketTransport;
wallet:
| Hex // Private key directly
| AbstractViemWalletClient // viem
| AbstractEthersSigner // ethers
| AbstractEthersV5Signer // ethers v5
| AbstractWindowEthereum; // window.ethereum (EIP-1193)
isTestnet?: boolean; // Whether to use testnet (default: false)
defaultVaultAddress?: Hex; // Vault address used by default if not provided in method call
signatureChainId?: Hex | (() => MaybePromise)Date.now()
nonceManager?: () => MaybePromise)
});
// Order
batchModify(args: BatchModifyParameters): Promise
cancel(args: CancelParameters): Promise
cancelByCloid(args: CancelByCloidParameters): Promise
modify(args: ModifyParameters): Promise
order(args: OrderParameters): Promise
scheduleCancel(args?: ScheduleCancelParameters): Promise
twapCancel(args: TwapCancelParameters): Promise
twapOrder(args: TwapOrderParameters): Promise
updateIsolatedMargin(args: UpdateIsolatedMarginParameters): Promise
updateLeverage(args: UpdateLeverageParameters): Promise
// Account
approveAgent(args: ApproveAgentParameters): Promise
approveBuilderFee(args: ApproveBuilderFeeParameters): Promise
claimRewards(): Promise
createSubAccount(args: CreateSubAccountParameters): Promise
evmUserModify(args: EvmUserModifyParameters): Promise
registerReferrer(args: RegisterReferrerParameters): Promise
reserveRequestWeight(args: ReserveRequestWeightParameters): Promise
setDisplayName(args: SetDisplayNameParameters): Promise
setReferrer(args: SetReferrerParameters): Promise
subAccountModify(args: SubAccountModifyParameters): Promise
spotUser(args: SpotUserParameters): Promise
// Transfer
perpDexClassTransfer(args: PerpDexClassTransferParameters): Promise
perpDexTransfer(args: PerpDexTransferParameters): Promise
spotSend(args: SpotSendParameters): Promise
subAccountSpotTransfer(args: SubAccountSpotTransferParameters): Promise
subAccountTransfer(args: SubAccountTransferParameters): Promise
usdClassTransfer(args: UsdClassTransferParameters): Promise
usdSend(args: UsdSendParameters): Promise
withdraw3(args: Withdraw3Parameters): Promise
// Staking
cDeposit(args: CDepositParameters): Promise
cWithdraw(args: CWithdrawParameters): Promise
tokenDelegate(args: TokenDelegateParameters): Promise
// Market
perpDeploy(args: PerpDeployParameters): Promise
spotDeploy(args: SpotDeployParameters): Promise
// Vault
createVault(args: CreateVaultParameters): Promise
vaultDistribute(args: VaultDistributeParameters): Promise
vaultModify(args: VaultModifyParameters): Promise
vaultTransfer(args: VaultTransferParameters): Promise
// Multi-Sign
convertToMultiSigUser(args: ConvertToMultiSigUserParameters): Promise
multiSig(args: MultiSigParameters): Promise
// Validator
cSignerAction(args: CSignerActionParameters): Promise
cValidatorAction(args: CValidatorActionParameters): Promise
}
`
#### SubscriptionClient
`ts
class SubscriptionClient {
constructor(args: {
transport: WebSocketTransport;
});
// Market
activeAssetCtx(args: EventActiveAssetCtxParameters, listener: (data: WsActiveAssetCtx | WsActiveSpotAssetCtx) => void): Promise
activeAssetData(args: EventActiveAssetDataParameters, listener: (data: WsActiveAssetData) => void): Promise
allMids(listener: (data: WsAllMids) => void): Promise
bbo(args: EventBboParameters, listener: (data: WsBbo) => void): Promise
candle(args: EventCandleParameters, listener: (data: Candle) => void): Promise
l2Book(args: EventL2BookParameters, listener: (data: Book) => void): Promise
trades(args: EventTradesParameters, listener: (data: WsTrade[]) => void): Promise
// Account
notification(args: EventNotificationParameters, listener: (data: WsNotification) => void): Promise
userEvents(args: EventUserEventsParameters, listener: (data: WsUserEvent) => void): Promise
userFundings(args: EventUserFundingsParameters, listener: (data: WsUserFundings) => void): Promise
userNonFundingLedgerUpdates(args: EventUserNonFundingLedgerUpdatesParameters, listener: (data: WsUserNonFundingLedgerUpdates) => void): Promise
webData2(args: EventWebData2Parameters, listener: (data: WsWebData2) => void): Promise
// Order
orderUpdates(args: EventOrderUpdatesParameters, listener: (data: OrderStatus
userFills(args: EventUserFillsParameters, listener: (data: WsUserFills) => void): Promise
userTwapHistory(args: EventUserTwapHistory, listener: (data: WsUserTwapHistory) => void): Promise
userTwapSliceFills(args: EventUserTwapSliceFills, listener: (data: WsUserTwapSliceFills) => void): Promise
// Explorer
explorerBlock(listener: (data: WsBlockDetails[]) => void): Promise
explorerTxs(listener: (data: TxDetails[]) => void): Promise
}
`
#### MultiSignClient
`tswallet
class MultiSignClient extends ExchangeClient {
constructor(
args:
& Omit, you should specify the following parameters:
& {
multiSignAddress: Hex; // Multi-signature address
signers: [ // Array of signers
AbstractWalletWithAddress, // First signer is the leader of a multi-sign transaction
...AbstractWallet[], // Any number of additional signers
];
},
);
// Same methods as ExchangeClient`
}
Transport acts as a layer between class requests and Hyperliquid servers.
#### HTTP Transport
HTTP transport is suitable for one-off requests or serverless environments.
`ts`
class HttpTransport {
constructor(options?: {
isTestnet?: boolean; // Whether to use testnet url (default: false)
timeout?: number; // Request timeout in ms (default: 10_000)
server?: { // Custom server URLs
mainnet?: { api?: string | URL; rpc?: string | URL };
testnet?: { api?: string | URL; rpc?: string | URL };
};
fetchOptions?: RequestInit; // A custom fetch options
onRequest?: (request: Request) => MaybePromise
onResponse?: (response: Response) => MaybePromise
});
}
#### WebSocket Transport
WebSocket transport has better network latency than HTTP transport.
`tstimeout
class WebSocketTransport {
constructor(options?: {
url?: string | URL; // WebSocket URL (default: "wss://api.hyperliquid.xyz/ws")
timeout?: number; // Request timeout in ms (default: 10_000)
keepAlive?: {
interval?: number; // Ping interval in ms (default: 30_000)
timeout?: number; // Pong timeout in ms (default: same as for requests)`
};
reconnect?: {
maxRetries?: number; // Maximum number of reconnection attempts (default: 3)
connectionTimeout?: number; // Connection timeout in ms (default: 10_000)
connectionDelay?: number | ((attempt: number) => number | Promise
shouldReconnect?: (event: CloseEvent) => boolean | Promise
messageBuffer?: MessageBufferStrategy; // Message buffering strategy between reconnection (default: FIFO buffer)
};
autoResubscribe?: boolean; // Whether to automatically resubscribe to events after reconnection (default: true)
});
ready(signal?: AbortSignal): Promise
close(signal?: AbortSignal): Promise
}
The import point gives access to all Hyperliquid-related types, including the base types on which class methods are
based.
The import point gives access to functions that generate signatures for Hyperliquid transactions.
#### Cancel order yourself
`ts
import { actionSorter, signL1Action } from "@nktkas/hyperliquid/signing";
const privateKey = "0x..."; // or viem, ethers
const nonce = Date.now();
const action = {
type: "cancel",
cancels: [
{ a: 0, o: 12345 },
],
} as const;
const signature = await signL1Action({
wallet: privateKey,
action: actionSorteraction.type,
nonce,
});
// Send the signed action to the Hyperliquid API
const response = await fetch("https://api.hyperliquid.xyz/exchange", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action, signature, nonce }),
});
const body = await response.json();
`
#### Approve agent yourself
`ts
import { signUserSignedAction, userSignedActionEip712Types } from "@nktkas/hyperliquid/signing";
const privateKey = "0x..."; // or viem, ethers
const action = {
type: "approveAgent",
signatureChainId: "0x66eee",
hyperliquidChain: "Mainnet",
agentAddress: "0x...",
agentName: "Agent",
nonce: Date.now(),
} as const;
const signature = await signUserSignedAction({
wallet: privateKey,
action,
types: userSignedActionEip712Types[action.type],
});
// Send the signed action to the Hyperliquid API
const response = await fetch("https://api.hyperliquid.xyz/exchange", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action, signature, nonce: action.nonce }),
});
const body = await response.json();
`
Hyperliquid requires chain 1337 for L1 actions (open order, change leverage, etc.). There are two ways to execute an
L1 action through an external wallet:
- (recommended) Create an
Agent Wallet
and execute all L1 actions through it
- Change the user's chain to 1337, however, the user will sign unreadable data
Hyperliquid doesn't have traditional market orders, but you can achieve market-like execution by placing limit orders
with tif: "Ioc" and prices that guarantee immediate execution:
- For buys: set limit price >= current best ask
- For sells: set limit price <= current best bid
Agent Wallet: Use agent's private key in constructor instead of master account's private key.
Vault and Sub-Account: Pass vault or sub-account address via vaultAddress parameter to methods or setdefaultVaultAddress` in constructor.
We appreciate your help! To contribute, please read the contributing instructions.