Get a free key
Hyperliquid · AI & API

Hyperliquid MCP server and API: ask in plain words, or call any route

Connect Claude, ChatGPT, Cursor or your own AI trading agent to Hyperliquid data and ask in plain words: 28 MCP tools, 47 REST routes, 12 live WebSocket channels, the vike-data CLI and alerts, on one free key; in Claude Desktop no key at all.

Ask your AI · Claude, ChatGPT, CursorConnect in a minute →

“Which Hyperliquid whales are long ETH right now, and how close are they to liquidation?”

hl_market hl_liquidations

“Send me a webhook when a Hyperliquid liquidation over $1M hits BTC.”

alerts_create
Connect

Connect your client in a minute

Pick your client; the first tab needs no key.

MCP server · Streamable HTTP · 28 Hyperliquid tools · 0 to 3 credits a call
https://data.vike.io/mcp
text
1. Settings → Connectors → Add custom connector
2. Name: Vike    URL: https://data.vike.io/mcp
3. Leave OAuth Client ID and Secret empty, click Add
4. Log into Vike in the tab that opens, click Allow
5. The Vike tools appear under the hammer icon
MCP tools

28 tools, grouped by the job they do

Each card: a question to copy, and the tools the agent calls for it, with their credits.

3 tools

Follow a wallet

“What does this Hyperliquid wallet hold right now, what has it made, and what did it trade this week? (paste an address)”

2 tools

Top traders

“Who are the top Hyperliquid traders this month by realized PnL, and how consistent are they?”

2 tools

Whale positions

“Which whales are long BTC on Hyperliquid right now, and how big are their positions?”

2 tools

Liquidations and leverage

“Where would BTC longs on Hyperliquid get liquidated, and who raised leverage today?”

3 tools

Orders, TWAPs and money moves

“Which TWAPs are running on Hyperliquid now, and who deposited more than $1M today?”

2 tools

The venue

“What were Hyperliquid's open interest and volume this week, and who holds the most HYPE?”

3 tools

Builder codes and vaults

“Which builder codes earned the most fees this month, and how is the HLP vault doing?”

3 tools

History for a backtest

“Find the Tesla market on Hyperliquid, give me its hourly candles for the last week, and a link to yesterday's file of every fill.”

3 tools

Watch it live

“What did hl.liquidations send in the last hour?”

5 tools

Alerts

“E-mail me every time this wallet opens, closes or flips a position on Hyperliquid.”

Every tool, the routes it runs and its command. A tool with several views takes view; the first is its default.
ToolCreditsWhat it doesRunsCLI
hl_wallet1One Hyperliquid wallet, by view. summary: /v1/hyperliquid/wallets/{address}
trades_summary: /v1/hyperliquid/wallets/{address}/trades/summary
vike-data hl wallet
hl_wallet_activity1A Hyperliquid wallet's event history, by view. fills: /v1/hyperliquid/wallets/{address}/fills
funding: /v1/hyperliquid/wallets/{address}/funding
ledger: /v1/hyperliquid/wallets/{address}/ledger
builders: /v1/hyperliquid/wallets/{address}/builders
vike-data hl wallet-activity
hl_wallet_trades1One Hyperliquid wallet's CLOSED round-trip trades, newest close first, keyset-paged: per trade the symbol, direction, open_ts / close_ts, entry and exit price, the largest size held (max_size_usd), traded volume_usd, realized_pnl and total_fee in USD and the… /v1/hyperliquid/wallets/{address}/trades vike-data hl wallet-trades
hl_leaderboard1Rank Hyperliquid wallets with the full risk set, by view. ranking: /v1/hyperliquid/leaderboard
flow_adjusted: /v1/hyperliquid/leaderboard/flow-adjusted
vike-data hl leaderboard
hl_perp_top_traders2Rank top Hyperliquid perp wallets by PnL / ROI / win rate / volume / trade count within a time window. /v1/hyperliquid/traders vike-data perp top-traders
hl_market1Hyperliquid market positioning, by view. positions: /v1/hyperliquid/positions
open_interest: /v1/hyperliquid/positions/symbols
hourly: /v1/hyperliquid/symbols/hourly
funding_rates: /v1/hyperliquid/funding-rates
vike-data hl market
hl_position_match2Reverse-lookup a Hyperliquid open position from share-card details (symbol + side + leverage + entry price). /v1/hyperliquid/positions/match vike-data perp find-position
hl_liquidations1Hyperliquid liquidations, by view. fills: /v1/hyperliquid/liquidations
risk: /v1/hyperliquid/liquidations/risk
heatmap: /v1/hyperliquid/symbols/{symbol}/liquidation-heatmap
vike-data hl liquidations
hl_leverage_changes1Hyperliquid positions whose leverage or margin mode differs between two consecutive complete position snapshots, newest first: one row per wallet and symbol with the previous and the new leverage, margin mode, side, size and entry price. /v1/hyperliquid/leverage-changes vike-data hl leverage-changes
hl_orders1Hyperliquid standing orders, by view. wallet: /v1/hyperliquid/wallets/{address}/orders
open: /v1/hyperliquid/orders
clusters: /v1/hyperliquid/symbols/{symbol}/order-clusters
vike-data hl orders
hl_twaps1Hyperliquid TWAP orders, one row per status line, newest first. /v1/hyperliquid/wallets/{address}/twaps
/v1/hyperliquid/twaps
vike-data hl twaps
hl_ledger1Hyperliquid deposits, withdrawals, transfers and vault events ACROSS wallets, newest first, with wallet and amount_usd (USD) on every row; min_usd keeps the large ones (most events are small transfers). /v1/hyperliquid/ledger vike-data hl ledger
hl_stats1Hyperliquid venue-wide hourly series, newest hour first, by view. ecosystem: /v1/hyperliquid/stats
volume: /v1/hyperliquid/stats/volume
vike-data hl stats
hl_hype_holders1The HYPE holder leaderboard: each wallet's spot HYPE balance plus staked HYPE, largest first, valued at one current HYPE price, with its pnl_cohort resolved at query time (label_basis is current; balances are last-known, so a stale balance can sit beside a… /v1/hyperliquid/hype/holders vike-data hl hype-holders
hl_builders1Hyperliquid builder codes (front-ends and bots that attach their address to an order and take a slice of the taker fee), by view. leaderboard: /v1/hyperliquid/builders
stats: /v1/hyperliquid/builders/stats
profile: /v1/hyperliquid/builders/{builder}
users: /v1/hyperliquid/builders/{builder}/users
fills: /v1/hyperliquid/builders/{builder}/fills
series: /v1/hyperliquid/builders/{builder}/series
vike-data hl builders
hl_vaults1Hyperliquid vaults across the platform, by view. list: /v1/hyperliquid/vaults
stats: /v1/hyperliquid/vaults/stats
flows: /v1/hyperliquid/vaults/flows
vike-data hl vaults
hl_vault1One Hyperliquid vault by address, by view. profile: /v1/hyperliquid/vaults/{vault}
depositors: /v1/hyperliquid/vaults/{vault}/depositors
flows: /v1/hyperliquid/vaults/{vault}/flows
series: /v1/hyperliquid/vaults/{vault}/series
vike-data hl vault
hl_ohlcv1Historical OHLCV candles for a Hyperliquid market, aggregated from HL's own executed fills, by view. candles: /v1/hyperliquid/ohlcv
latest: /v1/hyperliquid/ohlcv/latest
export: /v1/hyperliquid/ohlcv/export
vike-data candles hl
hl_archive1Index of the Hyperliquid Parquet archive and download links to its files. datasets: /v1/hyperliquid/archive/datasets
url: /v1/hyperliquid/archive/url
vike-data hl archive
stream_info0How to use the vike WebSocket stream (wss://stream.vike.io/v1/stream/<path>), read off the server's own registry: every path (hl, hl-cohorts, onchain, polymarket) with its channels; per channel its filter keys, each a list (with its maximum length), one… — vike-data stream info
stream_check_filter0Validate a stream subscribe message (or a channel + filter) with the SAME validator the stream server runs, without connecting. — vike-data stream check
stream_events1Stored events of ONE stream channel after a cursor, oldest first, with the stream's own filters: the REST catch-up of wss://stream.vike.io, for what a socket missed or a quick look without a socket. /v1/hyperliquid/stream-events vike-data stream events
alerts_create3Create an alert rule for the current user: an on-chain transfer alert (the default), a Hyperliquid or a Polymarket alert, chosen by alert_type. — vike-data alerts create
alerts_edit2Partial update of one of the user's alerts. — vike-data alerts edit
alerts_list0List the current user's alert rules. — vike-data alerts list
alerts_events1Read the events the current user's alert rules produced, oldest first (the feed behind GET /v1/alerts/events). — vike-data alerts events
alerts_list_channels0List the user's enabled email + webhook notification channels. — vike-data alerts channels

HL Cohorts has 2 tools of its own, hl_cohort_metrics and hl_segments: whales against smart money, cohort by cohort, on HL Cohorts.

CLI

Hyperliquid from the command line: vike-data

The same data from a terminal, and the command your coding agent runs. Open source, on npm.

bash
npm install -g @vike-io/cli     # Node.js 22.12 or newer
vike-data init                   # paste your key once
vike-data doctor                 # key, endpoint and tools in one check
CommandRuns
vike-data hl wallethl_wallet
vike-data hl wallet-activityhl_wallet_activity
vike-data hl wallet-tradeshl_wallet_trades
vike-data hl leaderboardhl_leaderboard
vike-data hl liquidationshl_liquidations
vike-data hl markethl_market
vike-data hl buildershl_builders
vike-data hl vaultshl_vaults
vike-data hl vaulthl_vault
vike-data hl ordershl_orders
vike-data hl twapshl_twaps
vike-data hl ledgerhl_ledger
vike-data hl leverage-changeshl_leverage_changes
vike-data hl statshl_stats
vike-data hl hype-holdershl_hype_holders
vike-data hl archivehl_archive
vike-data perp top-tradershl_perp_top_traders
vike-data perp find-positionhl_position_match
vike-data candles hlhl_ohlcv
vike-data stream hlthe live channels
vike-data alertsthe alert tools
  • vike-data call <tool> --args '{…}' runs any MCP tool by name.
  • vike-data install --claude adds the skill that teaches Claude Code to use the CLI.
  • Package @vike-io/cli 0.17.0.
WebSocket

12 live Hyperliquid channels

At wss://stream.vike.io/v1/stream/hl: every fill, liquidation and whale move as it lands, filtered on the server.

  1. Connect

    wss://stream.vike.io/v1/stream/hl with X-API-KEY on the handshake.

  2. Subscribe

    Send {"action": "subscribe", "id", "channel", "filter"}; up to 100 on one connection.

  3. Resume

    Keep the last cursor; subscribe with it after a drop and get what you missed, up to 3 days back.

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.liquidations",
                        "filter": {"min_usd": 100000}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["subject"], e["data"])
  • Every event has the same envelope: schema, event_id, source, kind, ts, cursor, chain, subject, data, labels. Keep each frame's cursor and dedupe on event.event_id: delivery is at least once.
  • The server sends {"type": "ping"} every 15 s; answer {"action": "pong"}. 3 missed pongs close the connection.
  • 1 connection per key on this path, 3 per account, 100 subscriptions on one connection; a newer connection wins and the older one is closed with 4410 and a resume cursor.
  • Close codes: 4401 key_revoked; 4408 slow_consumer; 4409 server_catching_up; 4410 replaced; 4411 memory_backstop; 4412 ping_timeout; 1011 a server fault; 1012 a server restart.
  • A list is OR inside a key, keys are AND across, an empty filter matches everything. A cohort or tier value unknown also matches an event with no label.
  • A channel is produced only while someone subscribes to it (and 15 minutes after).
  • Dropped? Subscribe again with your last cursor and get what you missed, up to 3 days back. Without a socket: GET /v1/hyperliquid/stream-events (its card) or the stream_events tool.
  • Connecting, subscribing and the frames you receive are not counted against the hourly limit.

Build a subscription

Pick a channel and fill the filters: the subscribe message and the CLI command update as you type.

Subscribe message
json
The same from the CLI
bash
Hyperliquid · WebSocket

hl.fills

Every perp fill as it lands: the wallet, its cohort labels, the coin, side, size in USD and, where the node says it, whether it opened, closed, flipped, increased or reduced the position. A subscribe without min_usd gets the fills of $1,000 or more; min_usd 0 is every fill.

Path
wss://stream.vike.io/v1/stream/hl
Filters
action, coin, min_usd, pnl_cohort, side, size_cohort, wallet
Default
min_usd 1,000
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
actionlist ≤ 50close, flip, increase, open, reduce
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
sideone valuebuy, sell
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.fills:0x6131f8e5d4eb73de6d030bf8e349efcc432eba7b:1793463688185:332800189911381",
 "source": "hl.fills",
 "kind": "fill",
 "ts": "2026-10-31T16:21:28.185Z",
 "cursor": "1793463688185-00000332800189911381",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x6131f8e5d4eb73de6d030bf8e349efcc432eba7b",
  "symbol": "xyz:CL"
 },
 "data": {
  "action": "reduce",
  "side": "buy",
  "size_usd": 61781.937000000005,
  "size_token": 603.575,
  "price": 102.36,
  "closed_pnl": 21.7287,
  "start_position": -4925.28,
  "position_after": -4321.705,
  "crossed": true,
  "trade_id": 332800189911381,
  "dex": "XYZ"
 },
 "labels": {
  "pnl_cohort": "3x rekt",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": -43439.253754530044,
  "size_cohort": "fish"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.fills",
                        "filter": {"coin": ["BTC"], "min_usd": 100000}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.positions

A whale's position change, sent beside the fill that made it: what the fill did to the position (open, increase, reduce, close or flip), the position before and after, and the wallet's labels; filter it by the wallet's tags too.

Path
wss://stream.vike.io/v1/stream/hl
Filters
action, coin, min_leverage, min_usd, pnl_cohort, side, size_cohort, tag, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
actionlist ≤ 50close, flip, increase, open, reduce
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
min_leveragenumbermust be a finite number >= 0
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
sideone valuebuy, sell
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
taglist ≤ 50must be a printable name of 1 to 64 characters
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.positions:0x6131f8e5d4eb73de6d030bf8e349efcc432eba7b:1793463688185:332800189911381",
 "source": "hl.positions",
 "kind": "position",
 "ts": "2026-10-31T16:21:28.185Z",
 "cursor": "1793463688185-00000332800189911381",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x6131f8e5d4eb73de6d030bf8e349efcc432eba7b",
  "symbol": "xyz:CL"
 },
 "data": {
  "action": "reduce",
  "side": "buy",
  "size_usd": 61781.937000000005,
  "size_token": 603.575,
  "price": 102.36,
  "closed_pnl": 21.7287,
  "start_position": -4925.28,
  "position_after": -4321.705,
  "crossed": true,
  "trade_id": 332800189911381,
  "dex": "XYZ"
 },
 "labels": {
  "pnl_cohort": "3x rekt",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": -43439.253754530044,
  "size_cohort": "fish"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.positions",
                        "filter": {"action": ["open", "flip"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.closed_trades

A round trip that closed: when it opened and closed, entry and exit price, size, realized PnL and fees.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, direction, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
directionone valuelong, short
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.closed_trades:0x17c3c8fdbcb7d1b240ce08965e09b1fc91cba868:BTC:short:473018254659257",
 "source": "hl.closed_trades",
 "kind": "closed_trade",
 "ts": "2026-11-02T14:11:24.151Z",
 "cursor": "1793630999000000-0x17c3c8fdbcb7d1b240ce08965e09b1fc91cba868-BTC-short-473018254659257",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x17c3c8fdbcb7d1b240ce08965e09b1fc91cba868",
  "symbol": "BTC"
 },
 "data": {
  "direction": "short",
  "open_ts": "2026-10-05T23:08:45.141000Z",
  "close_ts": "2026-11-02T14:11:24.151000Z",
  "duration_seconds": 2386959,
  "entry_price": 82742.48610952242,
  "exit_price": 0.0,
  "max_size_token": 65.89715999999954,
  "max_size_usd": 5589001.728239961,
  "volume_usd": 35491053.94947996,
  "realized_pnl": 203357.7737329998,
  "total_fee": 2926.3286200000007,
  "fill_count": 27212,
  "open_tid": 473018254659257,
  "baseline_adopted": false,
  "size_usd": 5589001.728239961
 },
 "labels": {
  "pnl_cohort": "3x smart",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": 821833.0928032473,
  "size_cohort": "3x whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.closed_trades",
                        "filter": {"wallet": ["0x25773676902085225ae5751075e4161369334897"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.liquidations

Every liquidation: the wallet, its cohort labels, the coin, the side that was closed and its size in USD.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, direction, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
directionone valuelong, short
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.liquidations:0xc0c7aa447bbc40a4a487dad6343b20f8e844cff1:SOL:1793463720000",
 "source": "hl.liquidations",
 "kind": "liquidation",
 "ts": "2026-10-31T16:22:00.000Z",
 "cursor": "1793463720000-0xc0c7aa447bbc40a4a487dad6343b20f8e844cff1-SOL",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0xc0c7aa447bbc40a4a487dad6343b20f8e844cff1",
  "symbol": "SOL"
 },
 "data": {
  "direction": "long",
  "size_usd": 410608.1475,
  "size_token": 4276.5,
  "mark_price": 96.015,
  "inferred": true
 },
 "labels": {
  "pnl_cohort": "3x rekt",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": -25940.84974099999,
  "size_cohort": null
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.liquidations",
                        "filter": {"min_usd": 100000}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.liq_risk

An open position whose price came close to its liquidation price, announced once when it enters the zone; it re-arms when it moves away.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, direction, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
directionone valuelong, short
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.liq_risk:0x082e843a431aef031264dc232693dd710aedca88:HYPE:long:1793616060",
 "source": "hl.liq_risk",
 "kind": "liq_risk",
 "ts": "2026-11-02T10:41:00.000Z",
 "cursor": "1793616060",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x082e843a431aef031264dc232693dd710aedca88",
  "symbol": "HYPE"
 },
 "data": {
  "asset": "HYPE",
  "direction": "long",
  "liq_ratio": 0.8703577332750073,
  "enter": 0.8,
  "prev": null,
  "mark_price": 85.725,
  "entry_price": 38.675565324008176,
  "liquidation_price": 74.611416685,
  "size_usd": 118304157.02849999,
  "leverage": 5.0,
  "snapshot_ts": "2026-11-02T10:41:00Z"
 },
 "labels": {
  "pnl_cohort": null,
  "pnl_cohort_basis": null,
  "pnl_cum_usd": null,
  "size_cohort": "4x whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.liq_risk",
                        "filter": {"coin": ["BTC", "ETH"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.top_positions

Each big coin's largest positions: one event when a position enters the top, leaves it or moves rank (event entered | left | moved).

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, direction, event, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
directionone valuelong, short
eventone valueentered, left, moved
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.top_positions:ETH:0x5b5d51203a0f9079f8aeb098a6523a13f298c060:entered:1793629560",
 "source": "hl.top_positions",
 "kind": "top_position",
 "ts": "2026-11-02T14:26:00.000Z",
 "cursor": "1793629560",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x5b5d51203a0f9079f8aeb098a6523a13f298c060",
  "symbol": "ETH"
 },
 "data": {
  "event": "entered",
  "rank": 1,
  "prev_rank": null,
  "top_n": 10,
  "direction": "short",
  "size_usd": 222141532.18031597,
  "size_token": 96925.8868,
  "entry_price": 2322.723237249773,
  "mark_price": 2291.87,
  "liquidation_price": 3700.6952196025,
  "leverage": 5.0,
  "unrealized_pnl": 2990477.381085038,
  "snapshot_ts": "2026-11-02T14:26:00Z",
  "first": true
 },
 "labels": {
  "pnl_cohort": "3x smart",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": 38550482.93637243,
  "size_cohort": "4x whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.top_positions",
                        "filter": {"coin": ["BTC"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.order_walls

A large resting order that appeared on the book or disappeared from it.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, event, min_usd, pnl_cohort, side, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
eventone valueappeared, disappeared
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
sideone valuebuy, sell
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.order_walls:592426159180:appeared",
 "source": "hl.order_walls",
 "kind": "order_wall",
 "ts": "2026-11-02T10:25:00.000Z",
 "cursor": "1793615100-00000000592426159180",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x31dea2516beee92135b96f464eeec3cf292a13f2",
  "symbol": "BTC"
 },
 "data": {
  "event": "appeared",
  "coin": "BTC",
  "side": "sell",
  "limit_px": 79407.0,
  "size_usd": 8328956.56,
  "remaining_usd": 8328956.56,
  "ts_placed": "2026-11-02T10:24:32.865Z",
  "first_seen": "2026-11-02T10:25:00.000Z",
  "last_seen": "2026-11-02T10:25:00.000Z",
  "oid": 592426159180
 },
 "labels": {
  "pnl_cohort": "3x smart",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": 5362809.680522572,
  "size_cohort": "4x whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.order_walls",
                        "filter": {"coin": ["BTC"], "event": "appeared"}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.twaps

TWAP status lines: a TWAP order activated, error, finished, stopped, terminated, waitingForTrigger.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, min_usd, pnl_cohort, side, size_cohort, status, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
sideone valuebuy, sell
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
statuslist ≤ 50activated, error, finished, stopped, terminated, waitingForTrigger
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.twaps:2494610:1793614010669043:terminated",
 "source": "hl.twaps",
 "kind": "twap",
 "ts": "2026-11-02T10:06:50.669Z",
 "cursor": "1793614010669043-2494610-1793614010669043-terminated",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x40f20b734d7d25ba0b6219e921382fa992a56a9e",
  "symbol": "xyz:CL"
 },
 "data": {
  "twap_id": 2494610,
  "side": "buy",
  "status": "terminated",
  "size": 15945.587,
  "executed_size": 9158.657,
  "executed_notional_usd": 912873.590198,
  "duration_minutes": 30,
  "reduce_only": false,
  "randomize": true,
  "placed_at": "2026-11-02T09:49:28.250000+00:00",
  "trigger_px": null,
  "trigger_above": null,
  "stop_px": null,
  "error": null,
  "size_usd": 1587622.37
 },
 "labels": {
  "pnl_cohort": "3x rekt",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": -630786.4677088035,
  "size_cohort": "2x dolphin"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.twaps",
                        "filter": {"status": ["activated"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.ledger

Deposits, withdrawals, transfers and vault events of every wallet (event_type accountClassTransfer, borrowLend, deposit, internalTransfer, rewardsClaim, send, spotTransfer, subAccountTransfer, vaultCreate, vaultDeposit, vaultDistribution, vaultLeaderCommission, vaultWithdraw, withdraw).

Path
wss://stream.vike.io/v1/stream/hl
Filters
event_type, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
event_typelist ≤ 50accountClassTransfer, borrowLend, deposit, internalTransfer, rewardsClaim, send, spotTransfer, subAccountTransfer, vaultCreate, vaultDeposit, vaultDistribution, vaultLeaderCommission, vaultWithdraw, withdraw
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.ledger:0x57dd78cd36e76e2011e8f6dc25cabbaba994494b:1793613669773:0x6569de99a42617cb66e30447e622be020134007f3f29369d093289ec6329f1b6",
 "source": "hl.ledger",
 "kind": "ledger",
 "ts": "2026-11-02T10:01:09.773Z",
 "cursor": "1793613669773000-0x57dd78cd36e76e2011e8f6dc25cabbaba994494b-1793613669773-0x6569de99a42617cb66e30447e622be020134007f3f29369d093289ec6329f1b6",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x57dd78cd36e76e2011e8f6dc25cabbaba994494b"
 },
 "data": {
  "event_type": "send",
  "amount_usd": -500119.0,
  "fee": 0.0,
  "token": "USDC",
  "counterparty": "0x71d0e11ebb6150cebe20cf62f798be1a50108c26",
  "hash": "0x6569de99a42617cb66e30447e622be020134007f3f29369d093289ec6329f1b6",
  "size_usd": 500119.0
 },
 "labels": {
  "pnl_cohort": "3x smart",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": 5809892.161684301,
  "size_cohort": "3x whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.ledger",
                        "filter": {"min_usd": 1000000}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.leverage

A position whose leverage or margin mode changed between two snapshots.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, direction, min_usd, pnl_cohort, size_cohort, wallet
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
directionone valuelong, short
min_usdnumbermust be a finite number >= 0
pnl_cohortlist ≤ 502x loser, 2x rekt, 2x smart, 2x winner, 3x loser, 3x rekt, 3x smart, 3x winner, loser, rekt, smart, unknown, winner
size_cohortlist ≤ 502x dolphin, 2x fish, 2x shark, 2x shrimp, 2x whale, 3x whale, 4x whale, dolphin, fish, shark, shrimp, unknown, whale
walletlist ≤ 1,000wallets are 0x followed by 40 hex characters

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.leverage:0x01e273fc08012db1b75e8ca93f8139bfac2ee977:BTC:1793614860",
 "source": "hl.leverage",
 "kind": "leverage",
 "ts": "2026-11-02T10:21:00.000Z",
 "cursor": "1793614860000000-0x01e273fc08012db1b75e8ca93f8139bfac2ee977-BTC-1793614860",
 "chain": "hyperliquid",
 "subject": {
  "wallet": "0x01e273fc08012db1b75e8ca93f8139bfac2ee977",
  "symbol": "BTC"
 },
 "data": {
  "prev_ts": "2026-11-02T10:16:00+00:00",
  "captured_at": "2026-11-02T10:19:41+00:00",
  "prev_captured_at": "2026-11-02T10:07:43+00:00",
  "dex_name": "HL",
  "change": "up",
  "leverage_prev": 7.0,
  "leverage": 8.0,
  "mode_prev": "cross",
  "mode": "cross",
  "position_side_prev": "long",
  "position_side": "long",
  "size_usd_prev": 14434371.116759999,
  "size_usd": 15722429.26275,
  "entry_price_prev": 78128.55916020906,
  "entry_price": 78117.7483785485,
  "direction": "long"
 },
 "labels": {
  "pnl_cohort": "3x smart",
  "pnl_cohort_basis": "live",
  "pnl_cum_usd": 828767.6863311598,
  "size_cohort": "whale"
 }
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.leverage",
                        "filter": {"coin": ["BTC"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.funding

Every perp's funding rate, premium, mid price and open interest at each 5-minute market snapshot.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin
Free APIArchiveStreamMCP

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.funding:BTC:1793614860",
 "source": "hl.funding",
 "kind": "funding",
 "ts": "2026-11-02T10:21:00.000Z",
 "cursor": "1793614860000000-BTC-1793614860",
 "chain": "hyperliquid",
 "subject": {
  "symbol": "BTC"
 },
 "data": {
  "snapshot_ts": "2026-11-02T10:21:00Z",
  "funding_rate": 1.25e-05,
  "premium": -0.0002409614,
  "mid_price": 78001.5,
  "open_interest": 40353.10018,
  "open_interest_usd": 3147602343.69
 },
 "labels": {}
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.funding",
                        "filter": {"coin": ["BTC", "ETH"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
Hyperliquid · WebSocket

hl.candles

Closed candles: one event each time a bar closes, intervals 1m, 5m, 15m, 30m, 1h, 4h, 1d, perp or spot, on the core venue or a HIP-3 dex.

Path
wss://stream.vike.io/v1/stream/hl
Filters
coin, dex, interval, market
Free APIArchiveStreamMCP
  • Intervals 1m 5m 15m 30m 1h 4h 1d, closed bars only. A spot pair matches its token (HYPE) and its Hyperliquid id (@107); market is perp or spot, dex HL for the core venue or a HIP-3 dex.
  • Each bar is event.data: open, high, low, close, volume, volume_usd, n_trades and closed: true; data.asset keeps the Hyperliquid id (@107 for a spot pair). event.ts is the bar's open. History of the same bars: GET /v1/hyperliquid/ohlcv.
  • Closed bars moved here from wss://data.vike.io/v1/stream, which answers HTTP 410 since 2026-11-02.

Filters

FieldTypeDescription
coinlist ≤ 200not a coin name (A-Z, 0-9 and : @ . _ / -, at most 32 characters)
dexlist ≤ 50not a dex name (A-Z and 0-9, at most 16 characters; HL is the core venue)
intervallist ≤ 5015m, 1d, 1h, 1m, 30m, 4h, 5m
marketlist ≤ 50perp, spot

A real event captured 2026-11-03

json
{
 "schema": "vike.event.v1",
 "event_id": "hl.candles:5m:xyz:SNDK:1793613000",
 "source": "hl.candles",
 "kind": "candle",
 "ts": "2026-11-02T09:50:00.000Z",
 "cursor": "1793613300-00300",
 "chain": "hyperliquid",
 "subject": {
  "symbol": "xyz:SNDK"
 },
 "data": {
  "interval": "5m",
  "market": "perp",
  "dex": "XYZ",
  "asset": "xyz:SNDK",
  "open": 1183.3,
  "high": 1186.1,
  "low": 1183.3,
  "close": 1185.2,
  "volume": 2102.737,
  "volume_usd": 2491744.5026,
  "n_trades": 631,
  "funding": null,
  "closed": true
 },
 "labels": {}
}

Subscribe

python
import json, os
from websockets.sync.client import connect   # websockets >= 14

with connect("wss://stream.vike.io/v1/stream/hl",
             additional_headers={"X-API-KEY": os.environ["VIKE_API_KEY"]}) as ws:
    ws.send(json.dumps({"action": "subscribe", "id": "s1", "channel": "hl.candles",
                        "filter": {"coin": ["BTC"], "interval": ["1m"]}}))
    for message in ws:
        frame = json.loads(message)
        if frame["type"] == "ping":
            ws.send(json.dumps({"action": "pong"}))
        elif frame["type"] == "event":
            e = frame["event"]
            print(e["ts"], e["data"])   # keep frame["cursor"] to resume
REST

47 routes under /v1/hyperliquid

Base URL https://data.vike.io/v1/hyperliquid, one header. Every route is also an MCP tool, named on its card.

REST

Authentication

  1. Sign in at vike.io

    Any account. No card, no plan to pick.

  2. Create a key

    On https://vike.io/account?tab=api-keys. Every key starts vk_; you can read it back later from the same page.

  3. Send the header

    X-API-KEY: vk_… on every request; OAuth clients send Authorization: Bearer.

SurfaceCredential
https://data.vike.io/v1/hyperliquid/…X-API-KEY, or an OAuth bearer token
https://data.vike.io/mcpOAuth sign-in for desktop clients (no key to copy), X-API-KEY for everything else
wss://stream.vike.io/v1/stream/hlEither header on the handshake, or ?token=vk_… for a browser, which cannot set WebSocket headers: a key in a URL can be logged, so use a header wherever you can
https://data.vike.io/v1/hyperliquid/archive/urlYour key asks for the file; the answer is a signed link, valid 7 days, and the link is the credential
  • Header names are case-insensitive: X-API-KEY and X-API-Key are the same header.
  • A key in a query string is never read on the REST API or MCP.
  • Every key has the same reach: there are no scopes.
REST

Limits

Requests20,000 per hour per key, a rolling hour; MCP calls share it
Per minute200 per minute per key, on /v1 only
Keysup to 3 active per account; each key is its own budget
Cost of a call1 per REST request (/ohlcv/export: 2); an MCP tool 0 to 3 credits
WebSocketnot counted: connecting, subscribing and the frames you receive
Archivedownloads not counted; asking for a link is one request, and the link is valid 7 days for any number of reads, range reads included
Price$0, nothing is billed
REST

Paging is keyset, not offset

A list answer carries nextCursor; send it back verbatim as cursor until it is null or a page comes back empty. There is no offset parameter: a keyset cursor makes every page cost the same and keeps rows from shifting between pages.

A cursor is bound to the query that issued it: reuse it after changing start / end, or on another route, and you get a 400 telling you to start again without one. A malformed cursor is a 400 too, never a silent page 1.

python
import os, requests

H = {"X-API-KEY": os.environ["VIKE_API_KEY"]}
url = "https://data.vike.io/v1/hyperliquid/positions"

cursor = None
while True:
    params = {"symbol": "BTC", "limit": 5000} | ({"cursor": cursor} if cursor else {})
    page = requests.get(url, params=params, headers=H, timeout=60).json()
    rows = page["positions"]          # the list key differs per route
    if not rows:
        break
    handle(rows)
    cursor = page.get("nextCursor")   # null on the last page
    if cursor is None:
        break

Try it: Position snapshots

Send replays an answer the API really returned for this exact URL; its nextCursor follows the rows.

symbol
limit
GET/v1/hyperliquid/positions?symbol={symbol}&limit={limit}

    
Press Send ▶ — the captured response appears here

    
REST

Errors

Branch on the status code, not the body: the body depends on which hop answered.

StatusMeaningBody
400The input was rejected: an unknown symbol or dex, a malformed identifier, a cursor from another query.{"detail": "…"}
401A missing, invalid or deactivated key.Turned away before the API runs, so the body can be an HTML page. Do not assume JSON.
404No such route or archive file.{"detail": "Not Found"}
410The stream catch-up: a cursor older than the events kept; the answer names the oldest cursor it accepts.{"detail": "…"}
422A parameter failed validation: the wrong type, or outside the bounds the route declares.{"detail": [ … ]}
429Over the hourly limit, or over 200 requests a minute on one key: wait the Retry-After seconds.Retry-After: 60 (hourly) or Retry-After: 1 (per-minute) header, JSON error body
503The data store failed. Not your request: retry with back-off.{"detail": "upstream unavailable"}
  • A failed query is never a 200 with an empty body. An empty list means there were no rows.
  • /traders and /positions/match run through the shared tool layer, which reports its own failures in-band, so an internal error there can arrive as a 400 carrying the error text.
  • MCP answers a bad credential with HTTP 401, a WWW-Authenticate: Bearer resource_metadata=... header (where an OAuth client starts discovery) and a JSON-RPC error (-32000, Invalid or missing API key). A rate-limit trip there is a real 429. Check the body, not just the status.
REST

Conventions

Every time is UTC.

Timestamps

WhereFieldFormat
Rows: positions, fills, liquidations, the feedsts, snapshot_ts, liq_tsISO-8601 string with offset, 2026-10-12T09:00:00+00:00
/ohlcvts (the bar's open)epoch milliseconds
/symbols/hourlytsepoch seconds
Query boundsstart, endISO-8601 UTC (or epoch ms on /ohlcv); start inclusive, end exclusive

Identifiers

FieldMeans
wallet, address0x and 40 hex characters
symbolthe instrument: BTC; a HIP-3 market with its dex, xyz:TSLA; a spot pair @107
cohorta rung of the chosen axis; the labels and ladders are HL Cohorts'

Paging envelopes

RoutesHow they page
/v1/hyperliquid list routeskeyset: nextCursor, a string or null, opaque and bound to the query that issued it; pass it back verbatim as cursor
/ohlcvno cursor: one page per request; move start and end
REST

Before you rely on it

What the field names do not tell you.

Reading a liquidation. On /liquidations direction is the side of the position that was closed: long means longs were liquidated, so the price fell. size_usd is the size of the closed position in USD, not what the trader lost.
Paging is by cursor. A list route returns nextCursor. Pass it back verbatim as cursor; do not build one. A cursor resumes after the last row's sort key, so rows written meanwhile do not shift the pages. Paging →
Cohort filters. axis and cohort narrow positions, the leaderboard and liquidation risk to one cohort. The ladders and their exact label strings are on HL Cohorts.
A label says when it was true. A row's pnl_cohort_basis (or the answer's label_basis) says whether its cohort label is point_in_time, as it was that hour, or current, today's label on an older row: right for "who is smart now", look-ahead in a backtest.
Fractions and percents. min_win_rate on the leaderboard is a fraction (0.6 = 60%); /traders takes and returns a percent.
symbol, not coin. symbol is the instrument parameter: BTC, a HIP-3 market xyz:TSLA. coin, its old name, is still accepted; do not send both.
Try it

Request builder: every route

Pick a route; the parameters come filled with real ids. The call is rebuilt as you type, and a captured route shows its real answer.

GET
bash
Endpoints

All 47 routes

Click a route to jump to its parameters and a call you can copy.

GET /v1/hyperliquid/leaderboard Leaderboard
GET /v1/hyperliquid/leaderboard/flow-adjusted Leaderboard Flow Adjusted
GET /v1/hyperliquid/traders Top Traders
GET /v1/hyperliquid/positions List Positions
GET /v1/hyperliquid/positions/match Position Match
GET /v1/hyperliquid/stats/volume Stats Volume
GET /v1/hyperliquid/symbols/hourly Assets Hourly
GET /v1/hyperliquid/hype/holders HYPE Holders
GET /v1/hyperliquid/funding-rates Funding Rates
GET /v1/hyperliquid/liquidations Liquidations
GET /v1/hyperliquid/liquidations/risk Liquidation Risk
GET /v1/hyperliquid/leverage-changes Leverage Changes
GET /v1/hyperliquid/orders Open Orders
GET /v1/hyperliquid/ledger Ledger Feed
GET /v1/hyperliquid/builders Builder Leaderboard
GET /v1/hyperliquid/builders/stats Builder Ecosystem Stats
GET /v1/hyperliquid/vaults Vault List
GET /v1/hyperliquid/vaults/flows Vault Flows Feed
GET /v1/hyperliquid/vaults/{vault} Vault Profile
GET /v1/hyperliquid/ohlcv/latest OHLCV Latest
GET /v1/hyperliquid/ohlcv/export OHLCV Export
GET /v1/hyperliquid/archive/datasets Archive file index
GET /v1/hyperliquid/archive/url Download link for one archive file
GET /v1/hyperliquid/stream-events Stream catch-up
Wallets

One wallet

Hyperliquid · REST · CLI · MCP

Wallet Summary

Route
GET /v1/hyperliquid/wallets/{address}
CLI
vike-data hl wallet
MCP
hl_wallet · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One wallet: equity, cohorts, risk metrics, lifetime external flow.

openedWithin bounds the open-positions block only — the equity, lifetime and metrics blocks are wallet-level totals with nothing per-position to filter, and bounding them would return a number that looks bounded and is not. Positions with no known open time are excluded from every bounded bucket, matching what /v1/hl-cohorts/segments and /v1/hl-cohorts/heatmap do, so cohort comparisons stay like-for-like.

open_positions.perp_bias = (long - short) / equity.account_value and open_positions.equity_exposure = (long + short) / equity.account_value, native perp account only: positions on the main dex over the native perp account value; builder-DEX positions are not included. Unbounded ratios, null with no main-dex position or no positive equity.

A wallet we hold nothing for (no equity snapshot, open position, trade, fill or ledger event) is a 400 naming it, not a block of zeros.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
windowquery1d | 7d | 30d | all. Default all
openedWithinquery24h | 7d | 30d | all. Default all

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897?window=30d"
Hyperliquid · REST · CLI · MCP

Wallet Trades

Route
GET /v1/hyperliquid/wallets/{address}/trades
CLI
vike-data hl wallet-trades
MCP
hl_wallet_trades · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Closed round-trip trades for one wallet.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
symbolqueryHL ticker, e.g. BTC. Omit for all
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 100, max 5000
cursorquerynextCursor from the previous page, verbatim

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/trades?limit=20"
Hyperliquid · REST · CLI · MCP

Wallet Trades Summary

Route
GET /v1/hyperliquid/wallets/{address}/trades/summary
CLI
vike-data hl wallet
MCP
hl_wallet · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Trade statistics for one wallet, overall and per coin.

Medians as well as means: one $4M outlier drags the mean trade size far from anything the wallet typically does, and the mean is where most leaderboards stop.

A wallet with no trade at all is a 400 naming it, not zeros. A wallet that has traded and was quiet in the requested window gets the zeros, which are true.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
windowquery1d | 7d | 30d | all. Default all

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/trades/summary?window=all"
Hyperliquid · REST · CLI · MCP

Wallet Fills

Route
GET /v1/hyperliquid/wallets/{address}/fills
CLI
vike-data hl wallet-activity
MCP
hl_wallet_activity · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Raw fills for one wallet.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
symbolqueryHL ticker
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
sidequerybuy | sell
limitqueryDefault 100, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/fills?limit=50"
Hyperliquid · REST · CLI · MCP

Wallet Funding

Route
GET /v1/hyperliquid/wallets/{address}/funding
CLI
vike-data hl wallet-activity
MCP
hl_wallet_activity · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Funding paid and received by one wallet.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
symbolqueryHL ticker
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 100, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/funding?limit=50"
Hyperliquid · REST · CLI · MCP

Wallet Ledger

Route
GET /v1/hyperliquid/wallets/{address}/ledger
CLI
vike-data hl wallet-activity
MCP
hl_wallet_activity · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Deposits, withdrawals, transfers and vault events for one wallet.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
event_typequeryOne of accountClassTransfer, borrowLend, deposit, internalTransfer, rewardsClaim, send, spotTransfer, subAccountTransfer, vaultCreate, vaultDeposit, vaultDistribution, vaultLeaderCommission, vaultWithdraw, withdraw. Validated against this fixed set
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 100, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/ledger?limit=50"
Hyperliquid · REST · CLI · MCP

Wallet Orders

Route
GET /v1/hyperliquid/wallets/{address}/orders
CLI
vike-data hl orders
MCP
hl_orders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

What became of one wallet's orders in a window: each order seen resting in it or filled in it, with its fills in the window and a status. Newest placement first; notes says what a snapshot cannot tell.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
fromqueryISO-8601 UTC. Default: 7 days before to
toqueryISO-8601 UTC. Default: the newest order snapshot. At most 30 days after from
symbolqueryHL perp ticker
statusqueryopen | filled | partially_filled | canceled_or_expired
limitqueryDefault 100, max 1000
cursorquerynextCursor from the previous page, verbatim

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/orders?limit=20"
Hyperliquid · REST · CLI · MCP

Wallet TWAPs

Route
GET /v1/hyperliquid/wallets/{address}/twaps
CLI
vike-data hl twaps
MCP
hl_twaps · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One wallet's TWAP orders: /twaps with the wallet pinned, wrapped as wallet, items, nextCursor.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
twap_idqueryOne TWAP id: every status line of that TWAP
symbolqueryHL ticker, e.g. BTC or xyz:AAPL
statusqueryOne of activated, waitingForTrigger, finished, terminated, stopped, error. Default: every status except error, a rejected placement rather than an order; status=error shows those rows
startqueryISO-8601 UTC. Default: no lower bound
endqueryISO-8601 UTC. Default: now. The window has no 31-day cap
orderqueryasc | desc. Default desc, newest first. order=asc returns the oldest events first and is the mode for following a feed: pass each nextCursor back verbatim. It orders by key, so a row the writer inserts late with an older key is not seen by a poller already past it: re-read a small overlap. An asc page with rows always carries a cursor; an empty one returns the cursor you sent, or on a first call null (the wallet already pins the place). So stop on an empty page, not on a null cursor. A desc page that comes back short carries no cursor. Anything else is a 400
limitqueryDefault 100, max 5000
cursorquerynextCursor from the previous page, verbatim. It pins the call that returned it: the feed, order, every filter and the start and end you sent. Changing or dropping any of them, start included, is a 400. It is also valid on /twaps?wallet= with the same parameters

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/twaps?limit=20"
Hyperliquid · REST · CLI · MCP

Wallet Builders

Route
GET /v1/hyperliquid/wallets/{address}/builders
CLI
vike-data hl wallet-activity
MCP
hl_wallet_activity · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Reverse lookup — which builders this wallet's flow is routed through.

share_of_volume is the share of the wallet's builder-routed volume. Fills placed without a builder code never reach this table, so it is not a share of the wallet's total trading.

Parameters

ParameterInDescription
addressrequiredpathThe wallet
windowquery1d | 7d | 30d | all. Default all
limitqueryDefault 50, max 500
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/wallets/0x25773676902085225ae5751075e4161369334897/builders?window=30d"
Traders

Leaderboards

Hyperliquid · REST · CLI · MCP

Leaderboard

Route
GET /v1/hyperliquid/leaderboard
CLI
vike-data hl leaderboard
MCP
hl_leaderboard · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Trader leaderboard carrying the full risk-metric set.

Drawdown, Calmar, recovery factor, profit factor, expectancy and streaks sit beside PnL: a wallet up 300% through a 70% drawdown is not the same find as one up 300% without, and a PnL-only board cannot tell them apart.

calmar_ratio and recovery_factor divide by CURRENT account value, so they are null under $1 of it, and sort=calmar, recovery_factor or roi skips those wallets (an emptied account used to lead with a ratio in the billions). profit_factor is capped at 999: 999 means no losing trade closed, or only a negligible one, not a measured ratio.

Parameters

ParameterInDescription
windowquery1d | 7d | 30d | all. Default 30d. The trades CLOSED in the current UTC day and the 1, 7, 30 or 365 days before it, so PnL, trade counts, win rates and tags are what was realized in the window
sortqueryOne of pnl, realized_pnl, roi, volume, trades, win_rate, long_win_rate, short_win_rate, account_value, profit_factor, expectancy, calmar, recovery_factor, max_drawdown, current_drawdown, avg_leverage, avg_duration, fees, win_streak, loss_streak. Default pnl. An unknown key is a 400, not a default
orderqueryasc | desc. Default desc
cohortqueryOne label on axis
axisquerysize | pnl | pnl_abs. Default size
min_tradesqueryMinimum closed trades in the window. Default 3, the floor /traders applies; pass 0 for no floor
min_win_ratequeryMinimum win rate
min_volumequeryMinimum total volume
limitqueryDefault 25, max 500
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/leaderboard?limit=10"
Hyperliquid · REST · CLI · MCP

Leaderboard Flow Adjusted

Route
GET /v1/hyperliquid/leaderboard/flow-adjusted
CLI
vike-data hl leaderboard
MCP
hl_leaderboard · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Leaderboard ranked on trading PnL, with external flow reported beside it.

An account-value delta is not a trading result: a wallet that deposits $1M and loses $50k reads as +$950k on any equity-delta ranking. This ranks on fills-derived realized PnL, which excludes deposits by construction, and returns the deposits, withdrawals and the daily attribution figures in the same row so a caller can see what was excluded rather than trust that something was.

Each row carries flow_unbalanced. It is true when the wallet had a send in the window, which is when the *attributed* block beside the rank is unreliable — ledger_events records send one-sided, so an outflow is seen while the matching inflow is not. The rank itself does not depend on attribution and is unaffected. The flag is reported, never used to filter: active traders move money constantly, and excluding them would empty the board rather than clean it.

Parameters

ParameterInDescription
windowquery1d | 7d | 30d | all. Default 30d. The trades CLOSED in the current UTC day and the 1, 7, 30 or 365 days before it, so PnL, trade counts, win rates and tags are what was realized in the window
limitqueryDefault 25, max 500
cursorqueryKeyset cursor
min_tradesqueryMinimum closed trades in the window. Default 3; 0 keeps any wallet with at least one

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/leaderboard/flow-adjusted?window=30d&limit=10"
Hyperliquid · REST · CLI · MCP

Top Traders

Route
GET /v1/hyperliquid/traders
CLI
vike-data perp top-traders
MCP
hl_perp_top_traders · 2 credits
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Top HL perp traders by the requested metric over the window.

Kept on the tool implementation rather than moved to the new engine: MCP and the AI chat call the same code, and a second ranking that disagreed with the one the assistant quotes would be worse than a near-duplicate route. /leaderboard is the richer, cursor-paged version.

Parameters

ParameterInDescription
windowquery1d | 7d | 30d | all. Effective default 30d
sortquerypnl | roi | win_rate | volume | trade_count | drawdown | account_value | long_pnl | short_pnl. Default pnl
orderqueryasc | desc. Default desc
min_tradesqueryMinimum closed trades. Floored at 3: omitting it or passing 0, 1 or 2 gives 3
min_win_ratequeryPercent, 0–100, not a fraction
min_volumequeryMinimum total volume
sizequeryNumber of traders, 1–100

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/traders?size=10"
Positions

Positions and open interest

Hyperliquid · REST · CLI · MCP

List Positions

Route
GET /v1/hyperliquid/positions
CLI
vike-data hl market
MCP
hl_market · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Position rows, current or historical.

open_only=true reads the latest-state table. Passing start/end switches to the historical snapshot table, which is 8.7 billion rows — bound it by symbol or wallet, or expect it to be slow.

Rows come in key order, not by size. The cursor pages on the table's primary key, so current positions are ordered by wallet, symbol, direction and historical ones by symbol, snapshot_ts, wallet (resolution=1h with wallet: by snapshot_ts, then symbol): limit=10 is the first ten wallets in address order, never the ten biggest positions. For the biggest, pass sort=size (below), or read /v1/hl-cohorts/symbols/{symbol}/size-breakdown (positioning by position-size bucket), /positions/symbols (open interest per symbol) or /v1/hl-cohorts/symbols/{symbol}/cohort-metrics (by cohort).

sort=size returns the limit biggest current positions of one symbol, ordered by size_usd descending, then wallet, then direction, from the same latest-state read as the default. It is a top-N, not a page: symbol is required, limit is at most 500, there is no cursor (nextCursor is always null), and start/end are refused; each violation is a 400 with a one-line reason. Every row additionally carries account_value: the wallet's NATIVE perp account value in USD at the newest snapshot (the same figure as equity.account_value on /wallets/{address}, so it leaves out a builder DEX's separate account), or null when it is unknown (a repaired value, or no row in the newest snapshot). It is never 0 for unknown. No per-position cumulative funding is served, because no per-position source exists that avoids scanning the funding table.

Every row declares its pnl-label provenance: pnl_cohort_basis (point_in_time | current, the same vocabulary labelBasis uses elsewhere) and pnl_cohort_as_of (the ISO hour the label was computed at, or null). Historical rows carry the point-in-time label from the hourly label table — not today's dictionary standing — with the current unlabelled tail (the newest hour or two) falling back to the dictionary and saying so per row; the envelope's label_computed block states the mode's source once. A historical pnl/pnl_abs cohort filter is answered from the same label table and therefore requires symbol or wallet alongside it.

A historical row's own label counts fills up to the end of its hour (label_computed.lookahead is true). For a backtest read label_causal instead: an object with the same keys (pnl_cohort, pnl_abs_cohort, pnl_cohort_as_of, pnl_cohort_basis) computed at the PREVIOUS hour, so it holds no later fill. It is null where that hour has no label for the wallet and is absent on current rows. The row's own label values are unchanged.

Parameters

ParameterInDescription
symbolqueryHL ticker, e.g. BTC
walletqueryOne wallet
cohortqueryOne label on axis
axisquerysize | pnl | pnl_abs. Default size
open_onlyqueryBoolean, default true. Latest open positions only
startqueryISO-8601 UTC. Setting either switches to history. Not before 2026-05-01
endqueryISO-8601 UTC. Setting either switches to history
limitqueryDefault 100, max 5000 (500 with sort=size)
cursorqueryKeyset cursor. Refused with sort=size
sortquerysize = the biggest positions of one symbol first. Default: key order. Current mode only; needs symbol; limit at most 500; no cursor
resolutionqueryHistory only (needs start). 5m = every snapshot, ~5 minutes apart. 1h = the last snapshot of each hour, ~12x fewer rows. Default: 1h when wallet is given (served from a wallet-sorted copy), 5m otherwise. A 5m read of one wallet is limited to 48 hours per request.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/positions?symbol=BTC&limit=10"
Hyperliquid · REST · CLI · MCP

OI Snapshot

Route
GET /v1/hyperliquid/positions/symbols
CLI
vike-data hl market
MCP
hl_market · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Market-wide open interest per coin at the latest snapshot, with the venue's own OI alongside our aggregate so the two can be reconciled.

Parameters

None.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/positions/symbols"
Hyperliquid · REST · CLI · MCP

Position Match

Route
GET /v1/hyperliquid/positions/match
CLI
vike-data perp find-position
MCP
hl_position_match · 2 credits
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Find open positions matching a symbol/side/leverage/entry profile — the 'who else is in this trade' query.

A dated sample: its entry price matched an open BTC short on 2026-11-03. Once that position closes the same call answers an empty list; send the coin, side, leverage and entry price of a position open now (/positions lists them).

Parameters

ParameterInDescription
symbolrequiredqueryHL ticker as listed, e.g. BTC, kPEPE, xyz:TSLA; case-insensitive for those spellings
siderequiredquerylong | short
leveragerequiredqueryNumeric, 0 or more. Matched within ±0.5 absolute. 0 finds cross-margin positions with no leverage recorded
entry_pricerequiredqueryNumeric, positive
mark_pricequeryTie-break among equally close entries (matches are ranked by entry-price distance first). Defaults to entry_price when omitted
limitqueryNumber of matches, 1–500

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/positions/match?symbol=BTC&side=short&leverage=5&entry_price=76327.4&limit=10"
Venue

Venue stats, funding and HYPE holders

Hyperliquid · REST · CLI · MCP

Stats

Route
GET /v1/hyperliquid/stats
CLI
vike-data hl stats
MCP
hl_stats · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Ecosystem time series: perp equity, open interest, position counts.

Parameters

ParameterInDescription
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 500, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/stats"
Hyperliquid · REST · CLI · MCP

Stats Volume

Route
GET /v1/hyperliquid/stats/volume
CLI
vike-data hl stats
MCP
hl_stats · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Hourly perp volume, whole venue or one coin.

volume is the traded notional counted once per trade (one side), the figure the candles report; until 2026-10-25 it counted both sides of every trade and was exactly twice that. The venue total (no symbol) is perp volume, builder-dex perps included, and leaves out spot and outcome markets; naming one of those as symbol still returns it. n_fills counts fill records, two per trade (one for each side).

Parameters

ParameterInDescription
symbolqueryHL ticker. Omit for the whole venue
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 500, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/stats/volume?symbol=BTC&limit=24"
Hyperliquid · REST · CLI · MCP

Assets Hourly

Route
GET /v1/hyperliquid/symbols/hourly
CLI
vike-data hl market
MCP
hl_market · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Hourly close + open interest + funding rate + premium, many assets at once.

Rows are arrays in columns order, not objects — a 120-day 10-asset window is 28,800 of them.

Parameters

ParameterInDescription
symbolsrequiredqueryComma-separated perp tickers, e.g. BTC,ETH,SOL. Max 64
daysqueryWindow length back from end. Default 120, range 1–400
startqueryISO-8601 UTC or epoch s/ms, inclusive. Overrides days
endqueryISO-8601 UTC or epoch s/ms, exclusive. Defaults to now

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/symbols/hourly?symbols=BTC&days=2"
Hyperliquid · REST · CLI · MCP

HYPE Holders

Route
GET /v1/hyperliquid/hype/holders
CLI
vike-data hl hype-holders
MCP
hl_hype_holders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

HYPE holder leaderboard — spot balance plus staked, per wallet.

pnl_cohort is resolved at query time and the envelope declares it (label_basis='current' + label_computed). Correct here, not a fallback: the leaderboard has no time axis — every row is last-known state, so a current label has no earlier row to contaminate. The caveat runs the other way: balances are last-known, so a stale balance can sit beside a fresh label. account_value is the wallet's perp account value and is null for a holder with no perp account on record (it used to read 0.0, the same as an account that really holds nothing).

Parameters

ParameterInDescription
orderqueryasc | desc. Default desc
limitqueryDefault 100, max 500
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/hype/holders?limit=10"
Funding

Funding rates

Hyperliquid · REST · MCP

Funding Rates

Route
GET /v1/hyperliquid/funding-rates
CLI
—
MCP
hl_market · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Hyperliquid funding rates: the latest of every perp, or one perp's hourly history.

funding_rate is the venue's hourly rate as a fraction (0.0000125 = 0.00125% an hour; Hyperliquid settles funding every hour, longs paying shorts when it is positive) and funding_rate_annualized is it x 8,760 (24 x 365), simple, not compounded (0.1095 = 10.95% a year). premium is the venue's premium of the perp over its oracle price, also a fraction. open_interest is one side, in coins, and open_interest_usd it x mid_price.

Without symbol, the board: one row per perp, native and builder-DEX (HIP-3, xyz:TSLA), its newest reading (taken every 5 minutes; ts says when), ranked by sort. as_of is the newest reading's time.

With symbol, the history: one row per UTC hour (ts is the hour's start), from data_from, the perp's first recorded hour (2026-04-02 for the oldest). funding_rate, premium, mid_price and open_interest are the means of the hour's readings (n_snapshots, 12 in a full hour), not the rate settled at the end of the hour, and the newest hour may still be filling. A symbol we hold no hour of is a 404.

Builder-DEX (HIP-3) perps: from 2026-04-22 13:00 to 2026-11-03 their hours are the rate the venue SETTLED at the end of the hour, rebuilt from its funding history, not a mean of readings; a value the venue never published (a market already delisted) is null.

Parameters

ParameterInDescription
symbolqueryHyperliquid perp ticker, e.g. BTC, or a builder-DEX (HIP-3) perp such as xyz:TSLA. Omit for the board: the latest funding of every perp. Given, that perp's hourly history. A spot or outcome market is a 400
sortqueryBoard only: oi | rate | abs_rate. Default oi, open interest in USD; abs_rate ranks by the size of the rate whatever its sign. A 400 with symbol
orderqueryasc | desc. Default desc: the board largest first, a history newest hour first
startqueryHistory only (needs symbol): ISO-8601 UTC, inclusive. Default: no lower bound (data_from)
endqueryHistory only (needs symbol): ISO-8601 UTC, inclusive. Default: now
limitqueryDefault 500, max 5000. The board holds about 350 perps, so the default is all of it
cursorquerynextCursor from the previous page, verbatim. It pins the call that returned it: resend the same symbol, sort and order, or the call is a 400. A board cursor also pins that board's time, so every page reads the same one

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/funding-rates"
Liquidations

Liquidations and leverage

Hyperliquid · REST · CLI · MCP

Liquidations

Route
GET /v1/hyperliquid/liquidations
CLI
vike-data hl liquidations
MCP
hl_liquidations · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Liquidation events, newest first: exact, from the node's fills since 2026-08-03; older rows inferred from position snapshots.

Since 2026-08-03 a row is the liquidated account's own fill, as the venue marked it: liq_ts is the fill's millisecond time, size_token and size_usd the size it closed (fills of one liquidation in the same millisecond summed) and mark_price the mark price the venue liquidated at. An older row is a position worth over $100 whose mark was within 5% of its liquidation price in one snapshot (taken about every 5 minutes) and that is gone from the next: liq_ts is the time of that snapshot, size and mark are the last values seen, a position closed by hand that close to its liquidation price is counted and a partial liquidation is not.

Each row's pnl_cohort is point-in-time — the label as it stood at the liquidation's own hour — where the hourly label table covers it, and the query-time dictionary label where it cannot; pnl_cohort_basis says which per row, and the envelope's label_computed declares the provenance and the two windows with no point-in-time label (rows before 2026-04-07, and the newest hours the label job has not yet published).

Parameters

ParameterInDescription
symbolqueryHL ticker
walletqueryOne wallet
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
directionquerylong | short
limitqueryDefault 100, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/liquidations?limit=20"
Hyperliquid · REST · CLI · MCP

Liquidation Risk

Route
GET /v1/hyperliquid/liquidations/risk
CLI
vike-data hl liquidations
MCP
hl_liquidations · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Share of each coin's open interest sitting close to liquidation.

Parameters

ParameterInDescription
axisquerysize | pnl | pnl_abs. Default size
cohortqueryOne label on that axis
limitqueryDefault 100, max 500
min_value_usdquerySmallest total open notional (USD) a coin needs to be ranked. Default 0 (no floor): the ranking is by percent_risk, so small markets with a few thousand dollars of interest lead it; raise this to keep only markets big enough for a cascade to matter.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/liquidations/risk"
Hyperliquid · REST · CLI · MCP

Liquidation Heatmap

Route
GET /v1/hyperliquid/symbols/{symbol}/liquidation-heatmap
CLI
vike-data hl liquidations
MCP
hl_liquidations · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Where liquidations would cluster if price moved — every open position's own liquidation price, binned and weighted by notional.

Parameters

ParameterInDescription
symbolrequiredpathHL ticker
binsqueryNumber of price bins. Default 50, min 5, max 500

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/symbols/BTC/liquidation-heatmap?bins=50"
Hyperliquid · REST · CLI · MCP

Leverage Changes

Route
GET /v1/hyperliquid/leverage-changes
CLI
vike-data hl leverage-changes
MCP
hl_leverage_changes · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Positions whose leverage or margin mode differs between two consecutive complete position snapshots, newest first.

One row per wallet and symbol, with the previous and the new value of leverage, margin mode, side, size and entry price. ts is when the later snapshot was written, not when the venue changed the setting. Snapshots are stamped every 5 minutes, but the positions behind them are captured about every 12 minutes, so changes arrive in batches.

Parameters

ParameterInDescription
walletqueryOne wallet, 0x plus 40 hex, any case
symbolqueryHL ticker, e.g. BTC or xyz:TSLA
changequeryup (leverage rose) | down (leverage fell) | mode (only the margin mode, cross or isolated, changed). Validated against this fixed set
min_leveragequeryMinimum new leverage, 0 or more. Default 0: no floor
startqueryISO-8601 UTC. Default: the 24 hours before end (before now when end is empty), unless wallet is given. Resuming an order=asc cursor starts from the cursor instead; a desc cursor keeps the 24-hour floor
endqueryISO-8601 UTC. Default: now. A window wider than 31 days is a 400 unless wallet is given
orderqueryasc | desc. Default desc, newest first. order=asc returns the oldest events first and is the mode for following a feed: pass each nextCursor back verbatim. It orders by key, so a row the writer inserts late with an older key is not seen by a poller already past it: re-read a small overlap. An asc page with rows always carries a cursor; an empty one returns the cursor you sent, or on a first call with no start or wallet, a cursor at the lower bound of the default window (null when one of them already pins the place). So stop on an empty page, not on a null cursor. A desc page that comes back short carries no cursor. Anything else is a 400
limitqueryDefault 100, max 5000
cursorquerynextCursor from the previous page, verbatim. It pins the call that returned it: the feed, order, every filter and the start and end you sent. Changing or dropping any of them, start included, is a 400. Without wallet, an asc cursor more than 31 days before end (before now when end is empty) is a 400 too: restart with start

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/leverage-changes?symbol=BTC&limit=20"
Orders and feeds

Standing orders, TWAPs and the ledger

Hyperliquid · REST · CLI · MCP

Open Orders

Route
GET /v1/hyperliquid/orders
CLI
vike-data hl orders
MCP
hl_orders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

The orders resting at one instant: every order in a 5-minute snapshot, or a rebuild from the sightings around it when no complete 5-minute snapshot exists.

Returns snapshotTs, source (l4_5m | state_12m), orders, nextCursor. The 5-minute snapshots start at 2026-10-23 21:45 UTC; before that, and after a stalled feed's last snapshot, the answer is rebuilt from the 12-minute checkpoints. A rebuilt answer for a past at lists only the orders seen before the instant and again after it, so short-lived orders can be missing, and its snapshotTs is the at floored to 5 minutes; an at inside an outage of either feed is answered the same way. Rows in key order (dex, symbol, side, oid); the cursor pins the snapshot.

Parameters

ParameterInDescription
symbolqueryHL perp ticker, e.g. BTC or xyz:TSLA. symbol and/or wallet is required
walletqueryOne wallet. symbol and/or wallet is required
atqueryISO-8601 UTC, floored to 5 minutes. Default: the newest snapshot. Not before 2026-07-29, not in the future
oidqueryOne order id
order_typequeryLimit | Stop Market | Stop Limit | Take Profit Market | Take Profit Limit | Trailing Stop Market
created_fromqueryISO-8601 UTC. Placed at or after
created_toqueryISO-8601 UTC. Placed at or before
limitqueryDefault 100, max 1000
cursorquerynextCursor from the previous page, verbatim

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/orders?symbol=BTC&limit=10"
Hyperliquid · REST · CLI · MCP

Order Clusters

Route
GET /v1/hyperliquid/symbols/{symbol}/order-clusters
CLI
vike-data hl orders
MCP
hl_orders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One symbol's standing orders within range_pct of the mid of the best resting bid and ask, bucketed by price: bid / ask by limit price, tp / sl by trigger price.

Trailing stops are not bucketed. For an at with no complete 5-minute snapshot at that instant (before 2026-10-23 21:45 UTC, or inside an outage) the book is rebuilt from the sightings on both sides of it: short-lived orders can be missing and reference_price then reflects the long-lived orders only. A call without at is never rebuilt: it is the newest snapshot, or the newest checkpoint while the 5-minute feed is stalled. For a past at, sizes can be later, smaller remaining sizes.

Parameters

ParameterInDescription
symbolrequiredpathHL perp ticker
atqueryISO-8601 UTC, floored to 5 minutes. Default: the newest snapshot
step_bpsqueryBucket width in basis points of the reference price. Default 10
range_pctqueryHalf-width of the price range, percent. Default 10
cohort_axisquerysize | pnl | pnl_abs. Default size
cohortqueryOne label on cohort_axis, by CURRENT labels: refused with at

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/symbols/BTC/order-clusters"
Hyperliquid · REST · CLI · MCP

TWAPs

Route
GET /v1/hyperliquid/twaps
CLI
vike-data hl twaps
MCP
hl_twaps · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

TWAP orders across wallets, one row per status line, newest first.

A line is a status CHANGE (activated, waitingForTrigger, then finished, terminated or stopped), not a slice fill: executed_size and executed_notional_usd are the cumulative totals when the line was written. Rejected placements (error) are hidden unless status=error. Rows sharing a ts keep a stable order, so a cursor never skips or repeats one.

Parameters

ParameterInDescription
walletqueryOne wallet, 0x plus 40 hex, any case
twap_idqueryOne TWAP id: every status line of that TWAP
symbolqueryHL ticker, e.g. BTC or xyz:AAPL
statusqueryOne of activated, waitingForTrigger, finished, terminated, stopped, error. Default: every status except error, a rejected placement rather than an order; status=error shows those rows
startqueryISO-8601 UTC. Default: the 24 hours before end (before now when end is empty), unless wallet or twap_id is given. Resuming an order=asc cursor starts from the cursor instead; a desc cursor keeps the 24-hour floor
endqueryISO-8601 UTC. Default: now. A window wider than 31 days is a 400 unless wallet or twap_id is given
orderqueryasc | desc. Default desc, newest first. order=asc returns the oldest events first and is the mode for following a feed: pass each nextCursor back verbatim. It orders by key, so a row the writer inserts late with an older key is not seen by a poller already past it: re-read a small overlap. An asc page with rows always carries a cursor; an empty one returns the cursor you sent, or on a first call with no start or wallet or twap_id, a cursor at the lower bound of the default window (null when one of them already pins the place). So stop on an empty page, not on a null cursor. A desc page that comes back short carries no cursor. Anything else is a 400
limitqueryDefault 100, max 5000
cursorquerynextCursor from the previous page, verbatim. It pins the call that returned it: the feed, order, every filter and the start and end you sent. Changing or dropping any of them, start included, is a 400. Without wallet or twap_id, an asc cursor more than 31 days before end (before now when end is empty) is a 400 too: restart with start. /twaps?wallet= and the per-wallet TWAP route are one feed: with the same parameters their cursors are interchangeable

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/twaps?limit=20"
Hyperliquid · REST · CLI · MCP

Ledger Feed

Route
GET /v1/hyperliquid/ledger
CLI
vike-data hl ledger
MCP
hl_ledger · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Deposits, withdrawals, transfers and vault events across wallets, newest first.

The cross-wallet twin of /wallets/{address}/ledger, with wallet on every row. A transfer between two wallets is one row per affected wallet with the same hash.

Parameters

ParameterInDescription
walletqueryOne wallet, 0x plus 40 hex, any case
event_typequeryOne of accountClassTransfer, borrowLend, deposit, internalTransfer, rewardsClaim, send, spotTransfer, subAccountTransfer, vaultCreate, vaultDeposit, vaultDistribution, vaultLeaderCommission, vaultWithdraw, withdraw. Validated against this fixed set
min_usdqueryMinimum absolute amount_usd, 0 or more. Default 0: no floor
startqueryISO-8601 UTC. Default: the 24 hours before end (before now when end is empty), unless wallet is given. Resuming an order=asc cursor starts from the cursor instead; a desc cursor keeps the 24-hour floor
endqueryISO-8601 UTC. Default: now. A window wider than 31 days is a 400 unless wallet is given
orderqueryasc | desc. Default desc, newest first. order=asc returns the oldest events first and is the mode for following a feed: pass each nextCursor back verbatim. It orders by key, so a row the writer inserts late with an older key is not seen by a poller already past it: re-read a small overlap. An asc page with rows always carries a cursor; an empty one returns the cursor you sent, or on a first call with no start or wallet, a cursor at the lower bound of the default window (null when one of them already pins the place). So stop on an empty page, not on a null cursor. A desc page the read finds short carries no cursor, but duplicate rows are dropped from a page after it is read, so a page with fewer than limit rows can still carry one: stop on an empty page. Anything else is a 400
limitqueryDefault 100, max 5000
cursorquerynextCursor from the previous page, verbatim. It pins the call that returned it: the feed, order, every filter and the start and end you sent. Changing or dropping any of them, start included, is a 400. Without wallet, an asc cursor more than 31 days before end (before now when end is empty) is a 400 too: restart with start

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/ledger?min_usd=1000000&limit=20"
Builder codes

Builder codes

Hyperliquid · REST · CLI · MCP

Builder Leaderboard

Route
GET /v1/hyperliquid/builders
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Builder leaderboard — fee revenue, routed volume, unique traders, fills.

sort=fee ranks the builder's own cut, not the trader's total cost; the two orderings differ materially because take rates range from ~0.2 bps to ~3.4 bps across the top of the board.

fee_usd and volume_usd cover every builder fill on record, older history included; trader_fee_usd covers only the newer, dollar-paid fills, so fee_usd / trader_fee_usd is not a take rate (it can pass 100%). Use fee_usd_node / trader_fee_usd: fee_usd_node is the builder's revenue over exactly the fills trader_fee_usd covers.

Every row carries active_days for the window. The history is still being filled in, so a long window can currently cover fewer days than it names — active_days beside the resolved window.start / window.end is how a client tells a quiet builder from an unfilled window instead of guessing.

market_share_pct is the row's routed notional over all Hyperliquid fill notional, measured over market_share_window_start → window.end — which can start LATER than window.start. Venue-wide volume exists only from the node's own retained fills, while the builder history reaches months further back via Hyperliquid's published CSVs, and that gap is permanent rather than a backlog. The share is therefore taken over the overlap; a number covering less than the requested window says so instead of quietly meaning something else.

Auditing it: divide share_volume_usd (the clamped numerator, shipped per row) by venue_volume_usd (top level). Do NOT use volume_usd — that is the row's full unclamped notional for the requested window, so on window=all it can exceed the numerator by more than 2x.

first_seen_lifetime is NOT window-scoped (first_seen is) — it is the builder's genuine first fill, which is the only one of the two that answers "how established is this front-end". Every *_pct here is percentage points, 0-100.

Parameters

ParameterInDescription
windowquery1d | 7d | 30d | all. Default 30d
sortqueryfee | volume | users | fills. Default fee
orderqueryasc | desc. Default desc
limitqueryDefault 50, max 500
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders?limit=10"
Hyperliquid · REST · CLI · MCP

Builder Ecosystem Stats

Route
GET /v1/hyperliquid/builders/stats
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Builder-code economics for the whole venue — the summary-card surface.

Answers what no per-builder route can: how many builders are active, how many distinct traders route through one, what share of all Hyperliquid fill notional carries a builder code, and how that moved day by day. lifetime.fee_usd is all-time and unwindowed. No fixed figure or start date is quoted here: builder history is imported from Hyperliquid's published per-builder fee CSVs, which reach back to the launch of builder codes, so both move as that import proceeds. Read lifetime.first_seen for the actual coverage start. (This line previously read "$21.7M since 2026-04-05" and was 40% low and eight months late within a day.)

Declared before /builders/{builder} because Starlette matches in declaration order and compiles {builder} to [^/]+: the other way round, this path returns a 400 for a builder literally named "stats".

Parameters

ParameterInDescription
windowquery1d | 7d | 30d | all. Default 30d

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders/stats"
Hyperliquid · REST · CLI · MCP

Builder Profile

Route
GET /v1/hyperliquid/builders/{builder}
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One builder: window totals plus per-asset and per-dex breakdowns.

fee_rate_bps is the realized effective rate (fee / volume); the venue's configured per-order rate is not in the data. fee_rate_bps_p50 is the median across fills that actually paid a builder fee, which is the closest observable thing to an advertised rate — 21% of rows pay the builder nothing and drag the mean.

user_volume_distribution is the concentration answer: users split into volume deciles, so "19k users" and "one whale plus a tail" stop looking the same. profitable_users is a per-wallet test (sum(closed_pnl) > 0), not a per-fill one — a wallet that won once and lost once is one loser. lifetime is unwindowed and is what makes a 30-day window interpretable.

Parameters

ParameterInDescription
builderrequiredpathBuilder address
windowquery1d | 7d | 30d | all. Default 30d
breakdown_limitqueryRows per breakdown. Default 100, max 1000

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders/0xb84168cf3be63c6b8dad05ff5d755e97432ff80b?window=30d&breakdown_limit=10"
Hyperliquid · REST · CLI · MCP

Builder Users

Route
GET /v1/hyperliquid/builders/{builder}/users
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

The wallets routing through one builder, ranked.

sort=pnl ranks sum(closed_pnl) — the traders' realized result, not the builder's. It is signed, and a builder whose users lose money is a different business from one whose users win.

Parameters

ParameterInDescription
builderrequiredpathBuilder address
windowquery1d | 7d | 30d | all. Default 30d
sortqueryvolume | fees | pnl. Default volume
orderqueryasc | desc. Default desc
limitqueryDefault 100, max 1000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders/0xb84168cf3be63c6b8dad05ff5d755e97432ff80b/users?window=30d&limit=20"
Hyperliquid · REST · CLI · MCP

Builder Fills

Route
GET /v1/hyperliquid/builders/{builder}/fills
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Raw builder-routed fills, newest first.

fee ships raw beside its own fee_token here, unlike every aggregate in this namespace: 0.95% of fills pay in a non-dollar token, so summing this column client-side without grouping by fee_token produces nonsense. fee_usd (the builder's slice) is dollars on every row.

Parameters

ParameterInDescription
builderrequiredpathBuilder address
symbolqueryHL ticker
sidequerybuy | sell
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 100, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders/0xb84168cf3be63c6b8dad05ff5d755e97432ff80b/fills?limit=50"
Hyperliquid · REST · CLI · MCP

Builder Series

Route
GET /v1/hyperliquid/builders/{builder}/series
CLI
vike-data hl builders
MCP
hl_builders · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Fee, volume, users and fills per bucket for one builder, newest first.

users is a distinct count per bucket and is not additive — summing the daily column double-counts anyone who traded on two days. A period total comes from /builders/{builder} over that period.

Parameters

ParameterInDescription
builderrequiredpathBuilder address
bucketquery1h | 1d. Default 1d
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 500, max 2000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/builders/0xb84168cf3be63c6b8dad05ff5d755e97432ff80b/series?bucket=1d&limit=30"
Vaults

Vaults and HLP

Hyperliquid · REST · CLI · MCP

Vault List

Route
GET /v1/hyperliquid/vaults
CLI
vike-data hl vaults
MCP
hl_vaults · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Every Hyperliquid vault, one row per vault family: current TVL, APR, the window's PnL, return, net flow, volume and fills, and the risk columns.

HLP and its sub-vaults are ONE row (child_vaults lists them), every dollar counted once. A window ends on the newest recorded day and reaches back 7, 30, 90 or 365 days; all is all recorded history. Windows are whole UTC days, from the close of the start day to the newest reading, so a figure can differ from the venue's own rolling week or month by up to one day's movement; tvl_usd is within a few percent of the venue's own figure. The top-level window states the resolved bounds, and each row its own start and partial: a vault younger than the window starts later. A family is measured from the first day inside the window on which all its open vaults are recorded (its start; partial true when that is later than the window's), every vault over that same span; if one of them has no record that day, pnl_usd, return_pct and apr_pct are null. A family's flows are the deposits into and withdrawals from its parent only: a sub-vault's own deposits and withdrawals are the parent moving money between its vaults, and pnl_usd nets them out. A closed sub-vault holds nothing and never holds a family's figures back.

pnl_usd is the equity change minus net deposits, null until a day after start is recorded (as return_pct is). return_pct is the chained share-price return in percentage points over the days with a measurable share-price step; days without one are skipped, and coverage (a fraction) says how much of the window was measured. It is null below 95% coverage, and null when a rebuilt day before 2026-10-27 holds a share-price jump of more than 2x either way that is not one of a pair (a jump and an equally large reversal on the next day, with no other such jump beside them, are both skipped). apr_pct annualises the vault's own 30-day return and is null for a vault, or a family, not recorded for all 30 days. net_flow_usd counts withdrawals and distributions as outflow. leverage is gross open notional over equity, leader_share_pct the leader's own share and top5_share_pct the five largest depositors' share, in percentage points, from the newest hourly reading (null for a vault not read in the last day, e.g. a closed one).

Parameters

ParameterInDescription
windowquery7d | 30d | 90d | 365d | all, whole UTC days ending on the newest recorded day. Default 30d
sortquerytvl | apr | pnl | return | net_flow | volume | age | leverage | top5_share. Default tvl
orderqueryasc | desc. Default desc
statusqueryopen | closed | all. Default open
depositsqueryany | open | closed: whether the vault accepts deposits. Default any
min_tvlqueryMinimum current TVL in USD. Default 0
qquerySearch, 2 to 64 characters: a case-insensitive part of the vault name, or an address prefix when it starts with 0x (a sub-vault's address finds its family). Matched literally: % and _ are not wildcards
limitqueryDefault 50, max 500
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults?sort=tvl&limit=10"
Hyperliquid · REST · CLI · MCP

Vault Stats

Route
GET /v1/hyperliquid/vaults/stats
CLI
vike-data hl vaults
MCP
hl_vaults · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Vault platform totals: TVL with every vault family counted once, flows over the window, vaults created per month.

user_vault_tvl_usd is the TVL outside the HLP family and hlp_net_flow_usd HLP's own net flow. withdrawals_usd includes distributions (a vault paying its depositors out), as net_flow_usd does. HLP moving money between its own sub-vaults is not a flow. vaults and open_vaults count vault families. With no recorded history the money totals and window are null.

Parameters

ParameterInDescription
windowquery7d | 30d | 90d | 365d | all, whole UTC days ending on the newest recorded day. Default 30d

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/stats?window=30d"
Hyperliquid · REST · CLI · MCP

Vault Flows Feed

Route
GET /v1/hyperliquid/vaults/flows
CLI
vike-data hl vaults
MCP
hl_vaults · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Deposits into and withdrawals from every vault, newest first, from the depositor's side.

Each row names the depositor, the vault and direction (in | out; amount_usd is unsigned). pnl_rank is the depositor's rank in the top 1,000 of /v1/hyperliquid/leaderboard?window=all, else null. vault is null on rows recorded before 2026-10-25 06:31 UTC.

Parameters

ParameterInDescription
windowquery7d | 30d | 90d | 365d | all, whole UTC days ending on the newest recorded day. Default 7d
min_usdquerySmallest flow in USD. Default 10000
typequeryall | deposit | withdraw | distribution | commission. Default all
smart_onlyqueryOnly depositors in the top 1,000 of /v1/hyperliquid/leaderboard?window=all. Default false
limitqueryDefault 100, max 1000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/flows?window=7d&min_usd=100000"
Hyperliquid · REST · CLI · MCP

Vault Profile

Route
GET /v1/hyperliquid/vaults/{vault}
CLI
vike-data hl vault
MCP
hl_vault · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One vault: registry fields, current TVL, APR, leverage, depositor concentration and all five windows.

windows holds 7d, 30d, 90d, 365d and all, each with start, end, partial, pnl_usd, return_pct, net_flow_usd, volume_usd, fills and coverage as on /vaults. leverage is open notional over equity; leader_share_pct and top5_share_pct are the leader's and the five largest depositors' shares in percentage points; active_depositors counts depositors holding at least $1. A parent vault's figures include its sub-vaults (child_vaults). With no recorded history windows, tvl_usd and apr_pct are null; an unknown address is a 404.

The vault's fills, trades and positions are served by /v1/hyperliquid/wallets/{address}/… with the vault's address.

Parameters

ParameterInDescription
vaultrequiredpathVault address

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/0xdfc24b077bc1425ad1dea75bcb6f8158e10df303"
Hyperliquid · REST · CLI · MCP

Vault Depositors

Route
GET /v1/hyperliquid/vaults/{vault}/depositors
CLI
vike-data hl vault
MCP
hl_vault · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

A vault's current depositors, largest share first.

share_pct is the depositor's share of the vault in percentage points and equity_usd its value at as_of; a parent vault's depositors own shares of the parent and its sub-vaults together, so the top-level equity_usd is theirs combined. pnl_usd is that value minus the cost basis of the depositor's current position (unrealised, as the venue reports it), all_time_pnl_usd that value minus everything the depositor ever put in net of what it took out. entered_at is the depositor's entry into the vault and lockup_until the end of the lockup after its last deposit (null when the vault has no lockup). pnl_rank is the depositor's rank in the top 1,000 of /v1/hyperliquid/leaderboard?window=all, else null. The list is complete: every depositor holding at least min_equity_usd, not only the largest 100; a wallet that has left the vault is never listed.

Parameters

ParameterInDescription
vaultrequiredpathVault address
sortqueryshare | pnl | all_time_pnl | entered. Default share
orderqueryasc | desc. Default desc
smart_onlyqueryOnly depositors in the top 1,000 of /v1/hyperliquid/leaderboard?window=all. Default false
min_equity_usdquerySmallest depositor equity in USD, at least 1. Default 1
limitqueryDefault 100, max 1000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/0xdfc24b077bc1425ad1dea75bcb6f8158e10df303/depositors?limit=20"
Hyperliquid · REST · CLI · MCP

Vault Flows

Route
GET /v1/hyperliquid/vaults/{vault}/flows
CLI
vike-data hl vault
MCP
hl_vault · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

One vault's own deposits, withdrawals, distributions and leader commissions, newest first.

counterparty is the depositor on deposits and withdrawals (on a deposit it is read from the depositor's own row of the same event; null when that row is missing or ambiguous). amount_usd is unsigned and direction is in or out. On a parent vault (HLP), the parent moving money into or out of its own sub-vaults is not a row.

Parameters

ParameterInDescription
vaultrequiredpathVault address
windowquery7d | 30d | 90d | 365d | all, whole UTC days ending on the newest recorded day. Default 30d
typequeryall | deposit | withdraw | distribution | commission. Default all
limitqueryDefault 100, max 1000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/0xdfc24b077bc1425ad1dea75bcb6f8158e10df303/flows?window=30d&limit=20"
Hyperliquid · REST · CLI · MCP

Vault Series

Route
GET /v1/hyperliquid/vaults/{vault}/series
CLI
vike-data hl vault
MCP
hl_vault · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Equity, share price, net flow and PnL of one vault per hour or day, oldest first.

nav is the chained share price, 1.0 at the first point of the first page; a missing step ends the chain (nav null from there), it is never read as 1.0. pnl_usd is the equity change minus the point's net flow. The cursor carries the previous point, so nav and pnl_usd continue across pages. A parent vault's (HLP's) series is its family's: equity_usd sums the parent and the sub-vaults read at that hour, or for a day at the parent's last reading of it (a closed one while it existed, a new one from its first reading), and net_flow_usd is the parent's depositors' deposits and withdrawals, so money moved between the parent and its sub-vaults is not PnL.

Parameters

ParameterInDescription
vaultrequiredpathVault address
bucketquery1d | 1h. Default 1d
startqueryISO-8601 UTC bounds
endqueryISO-8601 UTC bounds
limitqueryDefault 500, max 5000
cursorqueryKeyset cursor

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/vaults/0xdfc24b077bc1425ad1dea75bcb6f8158e10df303/series?bucket=1d&limit=30"
History

Candles and the Parquet archive

Hyperliquid · REST · CLI · MCP

OHLCV

Route
GET /v1/hyperliquid/ohlcv
CLI
vike-data candles hl
MCP
hl_ohlcv · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Hyperliquid candles, derived from executed fills.

Parameters

ParameterInDescription
symbolrequiredqueryPerp ticker (BTC), spot token (HYPE) or raw index (@107)
intervalquery1m | 5m | 15m | 30m | 1h | 4h | 1d, or Nt for N-trade bars. Default 1h
marketqueryperp | spot. Default perp
dexqueryHL core or a HIP-3 perp DEX, e.g. XYZ. Default HL. Builder DEXs are added over time, so do not hard-code a list
startqueryISO-8601 UTC or epoch ms, inclusive
endqueryISO-8601 UTC or epoch ms, exclusive
limitqueryDefault 500, clamped to 5000

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/ohlcv?symbol=BTC&interval=1h&market=perp&limit=48"
Hyperliquid · REST · CLI · MCP

OHLCV Latest

Route
GET /v1/hyperliquid/ohlcv/latest
CLI
vike-data candles hl
MCP
hl_ohlcv · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

The newest 1-minute candle of every symbol that traded in the last hour, in one request.

Parameters

ParameterInDescription
marketqueryperp | spot. Default perp
dexqueryHL core or a HIP-3 perp DEX, e.g. XYZ. Omit for every DEX; each row names its own
intervalqueryOnly 1m, the default. Any other value is a 400

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/ohlcv/latest"
Hyperliquid · REST · CLI · MCP

OHLCV Export

Route
GET /v1/hyperliquid/ohlcv/export
CLI
vike-data candles hl
MCP
hl_ohlcv · 1 credit
Cost
2 requests of the hourly limit
Free APIArchiveStreamMCP

Stream a window as NDJSON. Billed 2 credits up front, because the response is a stream and its row count is unknown when the usage is recorded.

Parameters

ParameterInDescription
symbolrequiredqueryAs on /ohlcv
intervalqueryAs on /ohlcv. Default 1h
marketqueryAs on /ohlcv. Default perp
dexqueryAs on /ohlcv. Default HL
startqueryAs on /ohlcv
endqueryAs on /ohlcv
limitqueryDefaults to the maximum, 5000

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/ohlcv/export?symbol=BTC&interval=1m&limit=1000"
Hyperliquid · REST · CLI · MCP

Archive file index

Route
GET /v1/hyperliquid/archive/datasets
CLI
vike-data hl archive
MCP
hl_archive · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Index of the Hyperliquid Parquet file archive: which UTC days exist and what is in each file.

One Parquet file per UTC day for fills (every fill) and positions (every 5-minute snapshot of every open position), from 2026-05-01. dates is newest first, each {"date": "YYYY-MM-DD", "streams": {"fills": {"rows", "bytes"}, "positions": {"rows", "bytes", "snapshots"}}}; snapshots is how many distinct 5-minute snapshots that day holds. schema lists every column of both datasets with its type and meaning. A day appears once it is complete (yesterday's files are published in the early UTC morning).

latest.positions is ONE file with the current open positions of every asset, replaced every 5 minutes (snapshot_ts, generated_at, rows, bytes, assets, note).

No daily or latest file has a direct URL and the folder cannot be listed: url_endpoint (/v1/hyperliquid/archive/url) answers with a 7-day link for exactly one file. The one exception is the free samples: samples_base is their public folder, and its files (manifest.json names them) are read with a plain GET or HEAD and no API key.

Parameters

None.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/archive/datasets"
Hyperliquid · REST · CLI · MCP

Download link for one archive file

Route
GET /v1/hyperliquid/archive/url
CLI
vike-data hl archive
MCP
hl_archive · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

A download link to ONE archive file, valid 7 days.

{"url", "expires_at", "expires_in", "dataset", "date", "bytes", "rows"}. The url is a presigned Cloudflare R2 link (host <account>.r2.cloudflarestorage.com): it needs no API key (the link is the credential), names exactly this file, and works for expires_in seconds (604800, 7 days) for any number of requests, so a reader that fetches byte ranges over HTTP (DuckDB, pyarrow) can use it directly. Once it expires, R2 answers 403: ask again. The call costs one credit and one request of the hourly budget like any route; the download itself spends none, and there is no download quota.

Parameters

ParameterInDescription
datasetrequiredqueryfills or positions. Anything else returns 400 naming both.
daterequiredqueryYYYY-MM-DD of a published UTC day, or latest (positions only: the file of the current open positions, replaced every 5 minutes). A day that is not published returns 400 naming the range that is.
redirectquery1 or true answers 302 with the link in Location; the JSON body is still sent, so a client that does not follow redirects keeps the answer.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/archive/url?dataset=positions&date=latest"
Live stream

Stream catch-up

Hyperliquid · REST · MCP

Stream catch-up

Route
GET /v1/hyperliquid/stream-events
CLI
—
MCP
stream_events · 1 credit
Cost
1 request of the hourly limit
Free APIArchiveStreamMCP

Stored events of one live-stream channel after a cursor, oldest first: the REST catch-up of wss://stream.vike.io/v1/stream/hl, for what a client missed while it was disconnected (events are kept 3 days). Pass the channel's filters as query parameters, as on the socket: a list as a comma list (wallet=0x..,0x..), a number as a number (min_usd=1000); an unknown filter, or one the channel does not take, is a 400 naming it.

Channels and their filters:

- hl.candles: coin, dex, interval, market - hl.closed_trades: coin, direction, min_usd, pnl_cohort, size_cohort, wallet - hl.fills: action, coin, min_usd, pnl_cohort, side, size_cohort, wallet (no min_usd means min_usd=1000, as on the socket) - hl.funding: coin - hl.ledger: event_type, min_usd, pnl_cohort, size_cohort, wallet - hl.leverage: coin, direction, min_usd, pnl_cohort, size_cohort, wallet - hl.liq_risk: coin, direction, min_usd, pnl_cohort, size_cohort, wallet - hl.liquidations: coin, direction, min_usd, pnl_cohort, size_cohort, wallet - hl.order_walls: coin, event, min_usd, pnl_cohort, side, size_cohort, wallet - hl.positions: action, coin, min_leverage, min_usd, pnl_cohort, side, size_cohort, tag, wallet - hl.top_positions: coin, direction, event, min_usd, pnl_cohort, size_cohort, wallet - hl.twaps: coin, min_usd, pnl_cohort, side, size_cohort, status, wallet

Returns {events: [{cursor, event}], next_cursor, has_more}. event is exactly what the socket sent, so dedupe on event.event_id. Pass next_cursor back as cursor while has_more is true. A window in which the channel was idle (nobody subscribed) comes as an item {cursor, gap} in its place. A cursor older than the retention is a 410 naming the oldest cursor accepted; omit cursor to start there.

The HL Cohorts channels have their own catch-up: /v1/hl-cohorts/stream-events.

Live, the same events arrive on the socket: vike-data stream hl --channel hl.liquidations. Channels, filters and real events: WebSocket.

Parameters

ParameterInDescription
channelrequiredqueryhl.candles, hl.closed_trades, hl.fills, hl.funding, hl.ledger, hl.leverage, hl.liq_risk, hl.liquidations, hl.order_walls, hl.positions, hl.top_positions, hl.twaps
cursorquerynext_cursor of the previous page or the cursor of a stream frame. Empty: the oldest retained event
limitqueryDefault 200, clamped to 1-1000

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hyperliquid/stream-events?channel=hl.liquidations&limit=50"
Alerts

Hyperliquid alerts by e-mail or webhook

No code: make one on your account page, ask your AI (alerts_create), or run the CLI. A webhook gets a signed POST.

Hyperliquid · Alert

A wallet opens, closes or flips

Type
hl_wallet
Free APIArchiveStreamMCP

hl_wallet = every fill of wallet (required), narrowed by actions, token_symbol (the coin) and min_value_usd.

Ask: “Send a webhook every time 0x2577…4897 opens, closes or flips a position on Hyperliquid.”

Create it on your account, no code →

json
{
 "label": "Whale fills",
 "alert_type": "hl_wallet",
 "wallet": "0x25773676902085225ae5751075e4161369334897",
 "actions": [
  "open",
  "close",
  "flip"
 ],
 "channels": [
  "webhook"
 ]
}
Hyperliquid · Alert

Whales fill big

Type
hl_cohort_fill
Free APIArchiveStreamMCP

hl_cohort_fill = every fill by wallets in pnl_cohorts / size_cohorts (at least one cohort is required, or it would match every large fill on Hyperliquid), requires min_value_usd >= 10000.

Ask: “E-mail me when a Hyperliquid whale with $10M or more fills over $1M.”

Create it on your account, no code →

json
{
 "label": "Whale fills over $1M",
 "alert_type": "hl_cohort_fill",
 "size_cohorts": [
  "4x whale"
 ],
 "min_value_usd": 1000000,
 "channels": [
  "email"
 ]
}
Hyperliquid · Alert

A big liquidation

Type
hl_liquidation
Free APIArchiveStreamMCP

hl_liquidation = every liquidation, optionally of one wallet, of cohorts, of one coin, above a min_value_usd floor.

Ask: “Send me a webhook when a Hyperliquid liquidation over $1M hits BTC.”

Create it on your account, no code →

json
{
 "label": "BTC liquidations over $1M",
 "alert_type": "hl_liquidation",
 "token_symbol": "BTC",
 "min_value_usd": 1000000,
 "channels": [
  "webhook"
 ]
}
Hyperliquid · Alert

A wallet nears liquidation

Type
hl_liq_proximity
Free APIArchiveStreamMCP

hl_liq_proximity = wallet (required) getting threshold of the way from entry to liquidation price.

Ask: “E-mail me when 0x2577…4897 is 80% of the way from its entry to its liquidation price.”

Create it on your account, no code →

json
{
 "label": "Whale near liquidation",
 "alert_type": "hl_liq_proximity",
 "wallet": "0x25773676902085225ae5751075e4161369334897",
 "threshold": 0.8,
 "channels": [
  "email"
 ]
}
One more type, HL Cohorts': hl_cohort_bias =the cohort index of token_symbol (required) crossing threshold by band, filtered by direction. HL Cohorts →

Fill and liquidation alerts notify on every event; a wallet alert once per coin, action and side of each evaluator pass (about every 10 s): the fills merged into one event, fills their count, min_value_usd applied to the merged total. Bias and proximity alerts notify once per crossing and re-arm after the value retreats by band.

Alerts

Webhooks and the alert feed

Register a webhook once and point any alert at it: the body, verifying the signature, testing it, retries, and the feed every alert fills.

Hyperliquid · Alerts · MCP tool

alerts_list_channels

Cost
0 credits a call
Free APIArchiveStreamMCP

Your enabled notification channels. No parameters.

Returns {"channels": [...]} with {id, channel_type, is_verified, label} per row. channel_type is email or webhook; a Discord connection is not listed, because Discord alerts are off. A webhook is is_verified: true once a delivery to it got a 2xx answer: an alert, or a test (at registration, or with alerts_test_webhook); webhooks registered before this check existed (early November 2026) show true regardless. An unverified webhook still receives its alerts.

Call it before creating an alert. A transfer alert that names a channel you have not set up is still created, and because it then has no channel of its own its notifications go to your account's email address. A Hyperliquid or Polymarket alert that names a webhook you have not registered is refused, so a rule is never left silent by accident.

Ask: “What notification channels do I have set up?”
Hyperliquid · Alerts · MCP tool

alerts_register_webhook

Cost
2 credits a call
Free APIArchiveStreamMCP

Registers an HTTPS webhook as a delivery channel. Vike POSTs signed JSON to the URL when your alerts fire, and once right away: a signed test event, whose result comes back in the answer.

ParameterTypeDefaultNotes
urlstringrequiredWebhook URL, https:// only, reachable from Vike's servers
secretstring—Your own HMAC secret, 16 characters or more. Leave it out and Vike generates one

Returns {"ok": true, "channel_id": ..., "channel_type": "webhook", "url_preview": "...", "signed": true, "test": {...}}, plus secret and secret_note when Vike generated the secret.

  • The secret can be shown again. A generated secret is in this answer, and you can show it again at any time on Account → Alerts → Channels (the Show secret button), so losing it does not require a rotation. alerts_rotate_webhook_secret issues a new one when you want one. A secret you passed yourself is not repeated back in this answer.
  • The test send. Right after the channel is stored, Vike POSTs one test event to the URL, signed and built like a real delivery: alert_id 0, alert_label Webhook test, alert_type and event.kind test, and an event.event_id of test: and 32 hex characters, new for every test. test is {"ok": true, "status": 200} for a 2xx answer, {"ok": false, "status": 401} for any other answer, or {"ok": false, "error": "timeout"} (also network, ssrf_refused, …) when none came. A failing test does not refuse the channel. Because the test is signed with the new secret, a receiver that checks signatures answers 401 or 403 until it has it: install the secret, then call alerts_test_webhook. The whole call, address check and test included, takes at most about 20 seconds.
  • https:// only for a new URL. A webhook registered over http:// before keeps working.
  • On the MCP server and over REST (POST /v1/alerts/channels/webhooks) only. The vike.io Ask AI chat does not register, rotate or test webhooks: a signing secret must not pass through a chat that stores the conversation.

The channel is yours and works for every rule you point at it.

The body

Every rule type sends one envelope: schema (vike.alert.v1), alert_id, alert_label, alert_type, triggered_at and event, the event that matched. A transfer also carries the flat keys the first webhook format had (chain, token, value_usd, from_address, to_address, tx_hash), so an old receiver keeps working. The envelope, a complete example and the shape of every event kind are on Alert feed and webhooks.

Verifying a delivery

The signing is Stripe-style. Each POST carries:

text
Content-Type: application/json
User-Agent: vike-alerts/1.0
X-Vike-Timestamp: <unix epoch seconds>
X-Vike-Signature: t=<ts>,sig=<hex hmac>[,sig=<hex hmac>]
X-Vike-Event-Id: <event_id>
X-Vike-Attempt: <1 for the first try>
X-Vike-Delivery-Id: <this delivery's id, the same on every try>

Compute HMAC-SHA256(secret, "<t>.<raw body>") with the t= of the header (the same value as X-Vike-Timestamp), hex-encode it, and compare it in constant time against every sig= value: accept the delivery if any of them matches. The header carries one sig= per valid secret: one normally, two for the 24 hours after a secret rotation (the new secret's first). A receiver that compares only one value rejects deliveries during those 24 hours. Check the raw bytes you received, before any JSON parser has touched them. Reject the delivery if the timestamp is more than about five minutes old — that is what stops a captured request being replayed.

Verify a delivery

python
import hashlib
import hmac
import time


def verify(secret: str, raw_body: bytes, signature_header: str, tolerance_s: int = 300) -> bool:
    """raw_body is the request body bytes exactly as received (do not re-serialise the JSON).
    Hostile input (a non-ASCII sig, `t=²`, 5000 digits, a lone surrogate, no header) is a False, never an exception."""
    try:
        parts = [p.split("=", 1) for p in signature_header.split(",") if "=" in p]
        ts = next((v for k, v in parts if k == "t"), "")
        if not ts.isdecimal() or len(ts) > 12 or abs(time.time() - int(ts)) > tolerance_s:   # replay window
            return False
        want = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest().encode()
        return any(hmac.compare_digest(want, v.encode()) for k, v in parts if k == "sig")   # ANY sig= may match
    except (ValueError, TypeError, AttributeError, OverflowError):     # UnicodeError is a ValueError
        return False

Every webhook registered now has a secret. A channel registered earlier without one is signed with an empty key, which proves nothing: give it a secret with alerts_rotate_webhook_secret.

Test webhooks on your own computer

To try a receiver before it is deployed, run it on localhost and expose it with a tunnel such as ngrok or cloudflared. Register the tunnel's https:// address as a webhook with alerts_register_webhook, and deliveries arrive on your machine. A tunnel's address is public for as long as it runs, so when you are done remove the channel under Account → Alerts → Channels, or rotate its secret.

Or skip the tunnel and send yourself the events you already have. This script reads your own alert feed, GET /v1/alerts/events, and POSTs each event to a local URL with the body and the headers of a real delivery, signed with your webhook's secret, so the verifier above accepts it. Set VIKE_API_KEY and VIKE_WEBHOOK_SECRET; TARGET_URL is http://localhost:8000/webhook unless you set it.

Forward your alerts to localhost

python
import hashlib
import hmac
import json
import os
import sys
import time
from datetime import datetime

import requests

API = os.environ.get("VIKE_API_BASE", "https://data.vike.io")
KEY, SECRET = os.environ["VIKE_API_KEY"], os.environ["VIKE_WEBHOOK_SECRET"]
TARGET = os.environ.get("TARGET_URL", "http://localhost:8000/webhook")
STATE, EVERY = "vike_forward.cursor", 5       # the cursor file; seconds between polls (720 requests an hour)


def delivery(row):
    """The body and the headers a real webhook delivery of this feed row carries."""
    ev = row["event"]
    body = {"schema": "vike.alert.v1", "alert_id": row["rule_id"], "alert_type": row["alert_type"], "event": ev,
            "alert_label": row["alert_label"] or f"alert #{row['rule_id']}",
            "triggered_at": datetime.fromisoformat(ev["ts"].replace("Z", "+00:00")).isoformat()}
    if ev["kind"] == "transfer":              # the flat keys of the earlier webhook format
        who, data = ev["subject"], ev["data"]
        bare = lambda v: v.lower().removeprefix("0x") if isinstance(v, str) else v
        usd = data.get("value_usd")
        body.update(chain=ev["chain"], token=who.get("token_symbol") or "", value_usd=None if usd is None else float(usd),
                    from_address=bare(who.get("from")), to_address=bare(who.get("to")),
                    tx_hash=bare(who.get("tx_hash") or data.get("tx_hash")))
    raw = json.dumps(body, sort_keys=True, separators=(",", ":")).encode()
    ts = int(time.time())
    sig = hmac.new(SECRET.encode(), f"{ts}.".encode() + raw, hashlib.sha256).hexdigest()
    hook = next((d["id"] for d in row["delivery"] if d["channel"] == "webhook"), 0)
    return raw, {"Content-Type": "application/json", "User-Agent": "vike-alerts/1.0", "X-Vike-Timestamp": str(ts),
                 "X-Vike-Signature": f"t={ts},sig={sig}", "X-Vike-Event-Id": ev["event_id"],
                 "X-Vike-Attempt": "1", "X-Vike-Delivery-Id": str(hook)}


cursor = open(STATE).read().strip() if os.path.exists(STATE) else ""
sent = set()
while True:
    try:
        more = True
        while more:                           # a page that says there is more is read at once
            r = requests.get(f"{API}/v1/alerts/events", headers={"X-API-Key": KEY},
                             params={"cursor": cursor, "limit": 500}, timeout=20)
            r.raise_for_status()
            page = r.json()
            for row in page["events"]:
                if row["id"] not in sent:
                    raw, headers = delivery(row)
                    status = requests.post(TARGET, data=raw, headers=headers, timeout=20).status_code
                    sent.add(row["id"])
                    print(row["event"]["event_id"], status, flush=True)
            cursor, more = page["next_cursor"], page["has_more"]
            open(STATE, "w").write(cursor)
    except (requests.RequestException, KeyError, ValueError) as e:
        print("error", type(e).__name__, file=sys.stderr, flush=True)    # the next poll tries again
    time.sleep(EVERY)
  • Steady and inside the limits. It asks the feed every 5 seconds: 720 requests an hour and 12 a minute, against the 20,000 an hour and 200 a minute the API publishes. Each call is one credit.
  • It keeps its cursor in vike_forward.cursor, so a restart continues where it stopped. The first run forwards everything the feed still holds, up to 15 days; delete the file to forward it all again. Within one run nothing is forwarded twice. After a restart the page it was on can be sent again, which a receiver that dedupes on alert_id and event.event_id (see below) drops.
  • It prints each forwarded event's id and the status your receiver answered, and nothing else; a failed call prints only the error's class name. The key and the secret are read from the environment and never printed.
  • Two headers are filled in as best they can be. X-Vike-Delivery-Id is the id of the event's webhook delivery in the feed (0 when the rule has no webhook channel), and X-Vike-Attempt is always 1.

Retries and duplicates

  • Answer with any 2xx within 20 seconds. That is one budget for the whole try: the address lookup, the connection, TLS, the request and your response's status line. After it the try is a timeout. A redirect is not followed and counts as a failure.
  • One delivery at a time per webhook. Vike never has two POSTs open to the same channel, and a slow or hanging endpoint delays only its own deliveries, never another channel's.
  • A failed delivery is tried again after 30 seconds, then after twice as long each time, up to an hour between tries, and given up on after 72 hours. A webhook that keeps failing is paused for a growing interval, at most 5 minutes, so one dead URL does not slow your other channels, and after three failures in a row Vike emails you once a day about it.
  • A 429 with a Retry-After header (seconds or an HTTP date) pauses that webhook for at least that long; the next try is never sooner, and never later than the 72 hours.
  • Delivery is at least once. A send that was cut off can arrive twice, so dedupe on the rule and the event: alert_id and event.event_id from the body (one event can match two of your rules, and each sends its own delivery). That pair is the replay-safe key, because the body is what the signature covers. X-Vike-Delivery-Id identifies the delivery too, but no header is signed: a captured request replayed inside the 5-minute window with a changed header still verifies, so dedupe on the header only alongside the body pair. A delivery sent again with alerts_resend_delivery keeps its X-Vike-Delivery-Id and counts on in X-Vike-Attempt. Events are not guaranteed to arrive in the order they happened.
  • Every delivery to a webhook, with its status, tries, last error and a Send again button, is listed under Account → Alerts → Webhook log for 15 days.
Ask: “Send my alerts to https://example.com/hooks/vike as well, with a signing secret.”
Hyperliquid · Alerts · MCP tool

alerts_test_webhook

Cost
1 credit a call
Free APIArchiveStreamMCP

Sends the signed test event to one of your webhook channels again — for example after your receiver installed a new secret.

ParameterTypeDefaultNotes
channel_idintegerrequiredThe webhook channel, its id from alerts_list_channels

Returns {"ok": true, "channel_id": ..., "test": {...}}, with test as at registration: {"ok", "status"} when the endpoint answered (ok for a 2xx), else {"ok": false, "error": ...}. The event is signed like a real delivery, with the current secret and, inside a rotation's 24 hours, the previous one too. Its X-Vike-Delivery-Id is its test: event id, new for every test. Nothing is queued, retried or stored. The same webhook channel not found as for a rotation.

Ask: “Send a test event to my webhook.”
Hyperliquid · Alerts · MCP tool

alerts_rotate_webhook_secret

Cost
2 credits a call
Free APIArchiveStreamMCP

Issues a new signing secret for one of your webhook channels.

ParameterTypeDefaultNotes
channel_idintegerrequiredThe webhook channel, its id from alerts_list_channels

Returns {"ok": true, "channel_id": ..., "secret": "...", "secret_note": "...", "previous_secret_valid_until": "..."}. The new secret is in this answer, like a generated one at registration, and can be shown again on Account → Alerts → Channels (Show secret).

For 24 hours after a rotation the old secret keeps signing as well: every delivery carries two sig= values, the new secret's first, until previous_secret_valid_until. A receiver that accepts a delivery when any sig= matches (the verifier above) keeps working while you swap the secret; one that compares a single value rejects deliveries for those 24 hours. Rotating again inside them ends the first overlap. A channel that had no secret rotates without an overlap (previous_secret_valid_until is null, one sig=). Install the new secret, then check it with alerts_test_webhook.

Another user's channel, an email channel and an id that does not exist all answer webhook channel not found.

Ask: “Rotate the signing secret of my webhook.”
Hyperliquid · Alerts · MCP tool

alerts_events

Cost
1 credit a call
Free APIArchiveStreamMCP

Reads the events your alert rules have produced, oldest first. To follow the feed, pass the returned next_cursor back as cursor.

ParameterTypeDefaultNotes
cursorstring—The previous page's next_cursor, passed back unchanged. Omit it for the oldest retained event
limitinteger100Events per page, 1 to 500
rule_idinteger—Only the events of this alert (its id from alerts_list). It must be a positive id; anything else is an error rather than a read of every rule

Returns {"events": [...], "next_cursor": "...", "has_more": false}. Each event carries id, rule_id, alert_label, alert_type, created_at, event (what happened) and delivery: one item per channel it went to, with the delivery's id (what alerts_resend_delivery takes), channel, channel_key, status, attempts, last_attempt_at, next_attempt_at (while it waits) and last_error as a code: http 500, timeout, network, tls, blocked, expired or error. An empty page returns the same cursor, so a poller keeps it and asks again. An event is in the feed as soon as it is recorded, before its email or webhook goes out. Events and their deliveries are kept for 15 days, and only your own alerts appear.

It is the same feed as GET /v1/alerts/events; the fields, the paging rules and every event shape are on Alert feed and webhooks.

Ask: “Show me what my alerts have fired since yesterday.”
Hyperliquid · Alerts · MCP tool

alerts_resend_delivery

Cost
1 credit a call
Free APIArchiveStreamMCP

Sends one of your deliveries again: the webhook or email of an event that failed, expired, or was lost on your side.

ParameterTypeDefaultNotes
delivery_idintegerrequiredThe delivery's id, from an event's delivery list in alerts_events

Returns {"id": ..., "status": "retry", "result": "queued"}. result is queued (it will be tried at once), already_queued (it was already waiting for a try; nothing changed) or sending (a try is under way right now).

  • Any status, up to 15 days after the event. A delivery that had already closed (sent, expired, skipped) gets a fresh 72 hours of retries.
  • It goes out with the same event, the same X-Vike-Delivery-Id, a new signature and the next X-Vike-Attempt, and is then retried like any delivery.
  • queued is a request, not a promise: the sender checks the rule and the channel again, so a delivery whose rule is paused or whose channel is disabled or deleted is skipped again, and a paused webhook delays the try.
  • An error, and no credit, for a delivery that is not yours or does not exist (the same answer for both), one whose event is older than 15 days (and, once the prune removed it, the same "does not exist"), and an unsupported one (its channel cannot carry that kind of event, so it would fail the same way).
  • Over REST it is POST /v1/alerts/deliveries/{id}/resend, and on the website the Send again button of Account → Alerts → Webhook log.
Ask: “The webhook of my last USDC alert never arrived: send it again.”
FAQ

Hyperliquid MCP and API FAQ

Is there a Hyperliquid MCP server?
Yes: https://data.vike.io/mcp, 28 tools for Hyperliquid wallets, positions, the leaderboard, liquidations, funding, vaults, builder codes, candles, the live stream and alerts. Claude Desktop signs in with OAuth and needs no key; other clients send a free key in X-API-KEY.
Can I build an AI trading agent on Hyperliquid data?
Yes. Any agent that speaks MCP over streamable HTTP calls the same tools; a script runs any of them with vike-data call <tool> --args '{…}', and every tool is also a REST route on the same key. A tool call costs 0 to 3 credits; nothing is billed. Your agent reads the data; it does not place orders.
Which Hyperliquid data can my AI read?
Any wallet's positions, PnL, fills, funding and ledger; the leaderboard; whale positions every 5 minutes; liquidations and where they would cluster; standing orders, TWAPs and leverage changes; vaults and builder codes; volume, open interest and funding; candles and every fill as daily Parquet files.
Is there a Hyperliquid WebSocket for liquidations, fills and whale moves?
Yes: wss://stream.vike.io/v1/stream/hl carries 12 channels, among them hl.liquidations, hl.fills, hl.top_positions and hl.candles, each filtered on the server by wallet, coin, size or cohort. Drop the connection and resume with your last cursor.
Can I get an alert when a Hyperliquid whale trades?
Yes, with no code: 4 alert types (a wallet's fills, whale-cohort fills, liquidations, a wallet nearing liquidation) by e-mail or a signed webhook, made on your account page, by your AI with alerts_create, or with vike-data alerts create.
Is there a Hyperliquid CLI?
Yes: npm install -g @vike-io/cli, then vike-data hl … for wallets, the leaderboard, markets, liquidations, vaults and builders, vike-data candles hl for candles and vike-data stream hl for the live channels.
How do I page through a long list?
Read nextCursor from the response and send it back as cursor until it is null. There is no offset parameter: a keyset cursor makes every page cost the same and keeps rows from shifting between pages.