Hyperliquid API Starter: Python SDK on Testnet with an API Wallet (2026)

Hyperliquid Read-only + testnet

PASS WITH FIXES Tested on Composer 2.5, , result: PASS WITH FIXES. We built this starter from the prompt and ran the public reads on testnet and mainnet (6/6 tests passing; ETH is asset 4 on testnet vs 1 on mainnet), a dry-run plan ETH buy 12 that meets the $10 minimum, and testnet agent-approval and order requests signed with fresh, unfunded throwaway keys. A testnet fill could not be tested: the exchange rejects unfunded accounts and the testnet faucet needs a prior mainnet deposit, which we don't make. No real keys or money. The prompt below includes the fixes from that run (Exchange construction, approve_agent's returned key, --mainnet on subcommands).

Short answer: The Hyperliquid API has two endpoints: POST /info for public reads (mids, order books, candles, account state) and POST /exchange for signed actions. Mainnet is https://api.hyperliquid.xyz; testnet is https://api.hyperliquid-testnet.xyz. This recipe builds a Python starter with the official SDK that reads both networks and places post-only testnet orders, signed by an API wallet that can trade but can't withdraw.

What are the key facts?

  • Two endpoints: POST /info (public reads, no signature) and POST /exchange (signed actions). Mainnet https://api.hyperliquid.xyz, testnet https://api.hyperliquid-testnet.xyz.
  • Official SDK: pip install hyperliquid-python-sdk (Info, Exchange, constants.TESTNET_API_URL).
  • API (agent) wallets sign trades for your main account but can't withdraw. Query balances with the main address, not the agent's.
  • Asset IDs differ between mainnet and testnet (we saw ETH = 1 on mainnet and 4 on testnet). Always look them up from meta.
  • Prices: max 5 significant figures and max 6 − szDecimals decimals (perps). Sizes round to szDecimals. Minimum order value $10.
  • Rate limit: 1,200 weight per minute per IP. l2Book and allMids weigh 2; most other info calls weigh 20.
DifficultyIntermediate
Time45–60 min
Cost$0 (testnet funds are mock USDC)
Works withClaude Code, Cursor, ChatGPT / Codex, Grok

What will you build?

A Python toolkit that reads Hyperliquid prices, books, candles and account state on mainnet or testnet, and places small post-only orders on TESTNET only through an API wallet, with correct price and size rounding, hard caps, a kill file and a scheduled cancel-all.

Who is it for?

Builders starting on Hyperliquid who want the read layer and the signing flow right before any strategy, and who want testnet to be the default.

Not for: Mainnet trading, leverage strategies or anything with real funds. The order path refuses to run anywhere but testnet.

Hyperliquid API Starter: Info Reads, Then Testnet Orders with an API Wallet

Hyperliquid's API is small and consistent: everything is a JSON POST. The traps are in the details. Asset IDs change between networks, prices have to fit a significant-figure rule, there's a $10 minimum, and agent wallets can't be used to look up balances. This recipe bakes all of that into the prompt so your AI tool doesn't learn it the hard way.

What prompt do you paste into your AI coding tool?

Works in Claude Code, Cursor, Codex/ChatGPT, Grok or any agent that can write files. Paste it into an empty folder. Read what it builds before you run anything.

You are building a Python starter for the Hyperliquid API. Reads work on
mainnet or testnet; ANY signed action works on TESTNET ONLY. Use only what is
documented at https://hyperliquid.gitbook.io/hyperliquid-docs or exists in
the official `hyperliquid-python-sdk`. If unsure, stop and ask me.

Project: hl-starter/
- Python 3.10+ (use `python3`), `hyperliquid-python-sdk`, `requests`, `python-dotenv`, `pytest`.
- hl_info.py (raw POST /info with requests, no signatures):
  - BASE: testnet https://api.hyperliquid-testnet.xyz by default; mainnet
    https://api.hyperliquid.xyz only when --mainnet is passed.
  - meta(), all_mids(), l2_book(coin) ({"type":"l2Book","coin":...};
    levels = [bids, asks], best first, each {px, sz, n}),
    candles(coin, interval="1h", hours=24) (candleSnapshot with
    req {coin, interval, startTime, endTime} in ms),
    user_state(address) (clearinghouseState), open_orders(address).
  - asset_info(coin) -> (asset index, szDecimals) looked up from meta() on
    the SAME network. Never hardcode asset ids: they differ between mainnet
    and testnet.
  - round_px(px, szDecimals): at most 5 significant figures AND at most
    (6 - szDecimals) decimals for perps; integer prices are always valid.
    round_sz(sz, szDecimals).
  - Backoff on 429. Rate limit is 1200 weight/min per IP; l2Book and
    allMids weigh 2, most other info requests 20. Cache meta for 5 minutes.
- hl_trade.py (signed, TESTNET ONLY):
  - exchange(): refuse unless env HL_MODE == "testnet"; build
    Exchange(Account.from_key(agent_key), constants.TESTNET_API_URL,
    account_address=HL_ACCOUNT_ADDRESS) where Account is
    `from eth_account import Account`. Exchange takes a LocalAccount
    object, not a hex string or address. Assert the URL is the testnet one.
    HL_AGENT_PRIVATE_KEY and HL_ACCOUNT_ADDRESS come from an env file
    OUTSIDE the repo (~/.config/hl-bot/.env, chmod 600).
  - check_order(): refuse if a KILL file exists; notional must be >= $10
    (exchange minimum) and <= $25; limit price must be at least 5% away
    from mid so the post-only order rests and doesn't fill.
  - build_order(coin, side, usd): size = usd / mid rounded to szDecimals
    (round up to reach $10), limit 10% away from mid, order type
    {"limit": {"tif": "Alo"}} (post-only).
  - place(): FIRST call exchange.schedule_cancel(now_ms + 60_000) as a
    dead-man switch (must be >= 5 s ahead; max 10 triggers per day), then
    exchange.order(...). Log request and response to logs/orders.jsonl.
  - cancel_all(): cancel every open order for HL_ACCOUNT_ADDRESS.
- approve_agent.py (run once, on testnet): with the MAIN testnet key
  loaded from the env file, build Exchange(Account.from_key(main_key),
  constants.TESTNET_API_URL) and call
  `result, agent_key = exchange.approve_agent(name)`. The SDK generates the
  agent key itself and returns it: save THAT agent_key. Do not generate
  your own key and do not save anything else, or you'll store a key that
  was never approved. Only write it if result["status"] == "ok".
  Write HL_AGENT_PRIVATE_KEY and HL_ACCOUNT_ADDRESS (the main address) to
  ~/.config/hl-bot/.env with chmod 600, and print only the agent ADDRESS
  (Account.from_key(agent_key).address). Never print keys.
- cli.py: `mids`, `book <coin>`, `candles <coin>`, `account`,
  `plan <coin> <buy|sell> <usd>` (dry run, prints the exact order),
  `place <coin> <buy|sell> <usd>`, `cancel-all`. `--mainnet` is allowed
  for reads only, and must work AFTER the subcommand
  (`cli.py book BTC --mainnet`): with argparse subparsers, add --mainnet to
  each read subcommand's parser, not only the top-level parser.
  `place` and `cancel-all` must not accept --mainnet at all.
- account/state queries always use HL_ACCOUNT_ADDRESS (the main account),
  never the agent address: an agent wallet has no balance of its own.
- .gitignore (.env, logs/), README, pytest tests (mock HTTP): rounding,
  best bid/ask, risk checks, "default mode sends nothing", and a grep test
  that hl_trade.py contains no mainnet URL.

Show me the file plan first. After writing, tell me exactly what to run.

How do you build it, step by step?

  1. Set up a clean folder (hl-starter) with the Safety Pack rules and .gitignore, then paste the prompt.
  2. Run the public reads, no key needed:
    python3 -m venv .venv && source .venv/bin/activate
    pip install hyperliquid-python-sdk requests python-dotenv pytest
    python3 cli.py mids
    python3 cli.py book ETH
    python3 cli.py book BTC --mainnet      # --mainnet goes after the subcommand
    python3 cli.py candles ETH
    
  3. Dry-run an order: python3 cli.py plan ETH buy 12. Check that the size is rounded to ETH's szDecimals, the price fits the 5-significant-figure rule, and the asset index matches testnet's meta (it differs from mainnet).
  4. Get testnet funds. The faucet at app.hyperliquid-testnet.xyz/drip gives mock USDC, but per the docs it only works for an address that has deposited on mainnet. Use a dedicated wallet for this, never your main one. See the Wallet-Key Safety Pack.
  5. Approve an API wallet on testnet: HL_MODE=testnet python3 approve_agent.py. It saves the agent key the SDK returned from approve_agent to ~/.config/hl-bot/.env, outside the repo. From then on, the bot signs with the agent key, which can trade but can't withdraw.
  6. Place one post-only testnet order: HL_MODE=testnet python3 cli.py place ETH buy 12. It sits 10% below the market, so it rests instead of filling. Check it with python3 cli.py account, then python3 cli.py cancel-all. If the account has no testnet funds, the exchange answers Must deposit before performing actions. That still proves your signing works, but you can't see a resting order or a fill until the account is funded. The scheduled cancel also clears it after 60 seconds.
  7. Test the kill switch: touch KILL and confirm place refuses. Remove it when you're done.
  8. Run pytest. The tests pass offline.

How do you test it in paper or demo mode first?

Testnet is the paper mode here. It's a separate network with mock USDC, its own asset IDs and its own order books. Keep these habits from day one:

  • Post-only (Alo) orders far from the market while you test plumbing. You're proving signing, rounding and cancels, not a strategy.
  • Dead-man switch: scheduleCancel before every session, so a crashed bot doesn't leave orders resting.
  • Log everything to logs/orders.jsonl. Hyperliquid's error strings ("Order must have minimum value of $10.", "Must deposit before performing actions.") are clear, so keep them.

If you want strategy-level paper trading on top, reuse the paper-ledger pattern from the kill switch and position limits recipe.

To watch funding across every perp without any key, see the read-only Hyperliquid funding-rate monitor. To see large trades and public positions, see the read-only whale and large-trade tracker.

What safety checks does it need before real money?

Tick every box before the bot touches real money. The full rules file, .gitignore and pre-commit hook are in the Safety Pack.

Which official docs did we check?

Endpoints and rules were checked against these pages on Oct 22, 2026. APIs change, so if something here disagrees with the official docs, trust the docs and tell us.

Frequently asked questions

Does the Hyperliquid API need an API key?

Not for reads. POST /info is public: mids, order books, candles and any address's account state. Trading needs signatures from your wallet or from an API wallet you approve. There's no separate key-and-secret pair like on centralised exchanges.

What is a Hyperliquid API wallet (agent wallet)?

It's a separate key that your main account authorises to sign trades for it. It can't withdraw funds. An account can have one unnamed agent and up to three named ones, plus two per subaccount, and approvals can carry an expiry. Query balances with the main address.

How do I get Hyperliquid testnet funds?

Use the faucet at app.hyperliquid-testnet.xyz/drip, which gives 1,000 mock USDC. Per the docs, it only works for addresses that have deposited on mainnet with the same address.

Can I test a Hyperliquid testnet fill without a mainnet deposit?

No. The testnet faucet only funds addresses that have deposited on mainnet, and an unfunded account gets Must deposit before performing actions. In our test run, signed requests from unfunded throwaway keys reached the testnet exchange and were rejected for that reason, which confirms signing, the testnet URL and the payload shape. A funded fill needs that mainnet deposit first, from a dedicated wallet.

Why was my Hyperliquid order rejected?

The usual causes are a price with more than 5 significant figures or too many decimals, a size not rounded to szDecimals, an order under $10, the wrong asset index (testnet and mainnet differ), or querying and signing with mismatched addresses.

What is the Hyperliquid API rate limit?

1,200 weight per minute per IP. l2Book, allMids and clearinghouseState weigh 2, most other info requests weigh 20, and an exchange action weighs 1 plus 1 per 40 orders in a batch. There are also per-address limits tied to trading volume.

Is there an official Hyperliquid Python SDK?

Yes: pip install hyperliquid-python-sdk. It provides Info for reads and Exchange for signed actions, including order, cancel, approve_agent and schedule_cancel, with constants.TESTNET_API_URL and constants.MAINNET_API_URL.

Hyperliquid Funding Rate Monitor: Read-Only Python Alerts (2026)

A tested AI prompt that builds a read-only Hyperliquid funding-rate monitor in Python: current and predicted funding per perp, annualized, with threshold alerts to the console or a webhook, on mainnet or testnet. No keys, no orders.

Hyperliquid Read-only (no keys) Beginner

Hyperliquid Whale Tracker: Read-Only Large-Trade Alerts in Python (2026)

A pre-tested AI prompt that builds a read-only Hyperliquid whale and large-trade tracker in Python: websocket trade alerts above a USD threshold, plus position and fill views for public addresses. No keys, no copy trading, informational only.

Hyperliquid Read-only (no keys) Intermediate

Trading Bot Wallet Security: Hot Wallet, Key & Approval Safety Pack (2026)

A tested AI prompt that builds four small wallet-safety tools for crypto and prediction-market bots: a secret scanner pre-commit hook, an env-file guard, a kill switch and a read-only wallet audit that flags balances and unlimited approvals.

Polymarket InternationalHyperliquid Read-only Beginner

More from the kitchen: Recipes by platform · Kalshi & Polymarket fee calculator · AI model test results · Safety Pack