Endpoints and Errors
Every WakeTrades API v1 endpoint, with its method and purpose, and the stable error codes an agent can rely on.
Base URL: https://waketrades.com/api/v1/. JSON in and out. Routes marked π need Authorization: Bearer <token> (Sign In With a Wallet). The full schema is in /openapi.json.
Account and Setup
| Method | Path | What it does |
|---|---|---|
POST |
/session/nonce |
Message to sign for sign-in |
POST |
/session/verify |
Signed message β session token (creates the account the first time) |
POST |
/session/revoke-all |
Signs out every session of the wallet, this one included |
DELETE |
/agent-link π |
Signs out every AI agent session of the wallet (an agent can sign itself out); the website stays signed in. A person connects an agent from the website's Profile, not through the API (Connect Your AI Agent) |
GET |
/me π |
Account, copy status, open positions, balance, network β see below |
GET |
/preview?planned= π |
What each exposure level would do with your balance and first leader, and the recommended level for that balance β see below |
PUT |
/settings π |
Leaders, exposure level, language; may return a warning. During sign-up, { "level" } alone is saved first (state stays setup, answer has next: "GET /leaders/suggested"); the next step needs at least one leader. ?dryRun=true checks it all and answers without saving (Dry Run) |
PUT |
/advanced π |
Settings of the Advanced level (every plan, free trial included; level advanced): size, exposure, alerts, markets, leverage, sides, stop per copy, daily loss limit β see Advanced Settings |
PUT |
/max-positions π |
{ "maxPositions": 5 } or null: maximum of open copies, at level advanced only |
GET |
/leaders/suggested?level= π |
Suggested trader for a level (default: your saved level) from our latest Monthly Report β see Suggested Traders. 400 invalid_level, 400 invalid_count, 404 no_suggestion before the first report |
PUT |
/leaders/name π |
{ "leader": "0xβ¦", "name": "β¦" }: a private name for one of your leaders, 24 characters at most ("" resets it). 400 leader_not_followed, 400 invalid_name |
GET |
/leaders/stats π |
Statistics of your leaders, from the cards already computed (no Hyperliquid read). A leader is null until their card exists: GET /leader/{address} computes it |
POST |
/agent π |
Address of the trading key to authorize |
POST |
/agent/approve π |
Relay your signed approveAgent to Hyperliquid |
POST |
/agent/verify π |
Accept the Terms, confirm the key, start copying; may return a warning |
POST |
/account/unified π |
Body {}. Switch the Hyperliquid account to a Unified Account with the trading key, no wallet signature. Call it right after /agent/verify β see Unified Account |
GET PUT DELETE |
/webhook π |
Alert channel for agents (Webhooks) |
PUT |
/notifications π |
{ "muted": true } stops position-move alerts |
POST |
/telegram/link π |
{ "name" } (optional wallet name, 1 to 20 characters) β { url, oidcUrl, expiresInSec }: a link to open the WakeTrades Telegram bot, valid 15 minutes; Telegram is an alert channel like the webhook. 400 invalid_wallet_name |
POST |
/telegram/unlink π |
Unlink Telegram β { state }; copying continues. 409 telegram_not_linked |
POST |
/notices/dismiss π |
{ "id" } hides a notice of status.notices for good β { notices }. 400 unknown_notice |
POST |
/report/collapse π |
{ "edition": "YYYY-MM" } β { reportCollapsed }: folds the Monthly Report card until the next edition (used by the web app). 400 invalid_edition |
PUT |
/order-mode π |
{ "mode": "market" } or "limit": how copies enter β see Order Mode |
GET |
/feedback π |
Your last 30 messages to the team and the team's replies, oldest first: { canWrite, unread, messages: [{ from: "you" | "team", text, at }] } |
POST |
/feedback π |
{ "message": "β¦", "email": "β¦" } (email optional): feedback, a bug report or an idea, to the team. Activated accounts only (403 account_required before); 1β2,000 characters; up to 10 per 24 hours (429 feedback_limit). Returns 201 { sent, emailed } |
POST |
/feedback/read π |
Mark the team's replies as read: { unread: 0 } |
Copying
| Method | Path | What it does |
|---|---|---|
GET |
/positions π |
Copied positions with stop and take profit, and openedAt (ms) for their age. Prices and PnL may be up to 30 seconds old, longer during a Hyperliquid outage or heavy load |
GET |
/orders?n=50&before=<ms> π |
Copy orders, including skipped trades and why; n 1 to 100, default 50 |
GET |
/journal?n=20 π |
Recent events (the same ones as the webhook) |
GET |
/history.csv π |
Closed copies as CSV (after a first payment) |
POST |
/pause π |
Stop opening new copies; open ones stay managed |
POST |
/resume π |
Resume copying (needs Telegram or a webhook) |
POST |
/close-position π |
{ "coin": "ETH" } closes one copy at market. If you close a copy yourself, the leader's later adds on that coin are not copied; their next new position is |
POST |
/close-losing π |
Close at market the copied positions currently in loss (an action of the drawdown alert) |
POST |
/close-all π |
Close every copy at market and pause |
POST |
/emergency-stop π |
Emergency stop: the same as /close-all, with what it doesn't do (keyRevoked: false) β see Security |
GET |
/stream π |
WebSocket: every event and your leaders' moves live, commands back β see Real-Time Stream |
Plans
| Method | Path | What it does |
|---|---|---|
GET |
/offer |
Public prices |
GET |
/subscription π |
Receiver, offers, trial and plan dates, payments. founder: your founder price applies. Before activation, founderOnActivation: true while founder seats remain (the same rule as /offer): the offers then show the founder price the account gets when its trial starts. In payments, tx_hash is null until the hourly reconciliation with Hyperliquid's ledger fills it (within the hour) |
GET |
/pay/prepare?plan=&chainId= π |
The payment to sign: usdSend from your free perps USDC, or sendAsset from your spot USDC (Pay With USDC) |
POST |
/pay π |
Relay your signed payment and apply the plan. ?dryRun=true checks it all without relaying (Dry Run); accepts an Idempotency-Key |
Monthly Report
| Method | Path | What it does |
|---|---|---|
GET |
/report?level=&month= π |
Up to 5 traders per exposure level (prudent, equilibre, risque), picked by our filters then ranked on what a copy would have made over 90 days, no scalpers, with what copying each one would have earned and lost at that level over 90 days, their type, win rate, profit factor, trades per month, holding time and positions open at once (average and peak). The latest edition by default, or month=YYYY-MM |
GET |
/report.md?level=&month= π |
The same report as Markdown (text/markdown), same access: to read it as an agent or paste it into an assistant |
GET /report answers 404 no_edition if no edition is published yet, and GET /leaders/suggested answers 404 no_suggestion: choose a trader yourself by address and check it with GET /leader/{address}.
With a paid plan in progress, access is full. Otherwise, during the free trial for example, it's preview: each entry keeps its rank, its type and what copying it would have earned and lost at that level (rounded to 1%), the trader's own return over 90 days and 6 months and win rate (leader.return90d, leader.return6m, leader.winRate90d, rounded to 1%) and profit factor (leader.profitFactor90d, one decimal), without name, address or the trader's other account figures, and has locked: true. Both views include yourCopy: for each level, the top 3 traders copied together at that level's size, by balance (1,000 to 25,000 USDC) β result, median, 1-in-10 and worst 30 days, worst drop, alerts crossed, peak exposure and margin (yourCopy is simulated: limit orders at the trader's price, then market after 1 min if unfilled, about 30 s after the trader, 0.026% average fee per side, funding not included). With full, each entry's copy also gives trades (the trader's trades in the 90 days), copies, simShare and skipped (why trades were not copied), and leader.stressBtc10 (the trader's estimated move if BTC drops 10% in a day). Both views also include yourResults, the real figures of the signed-in wallet for the edition's month: { ready: false } until a month of copy trading is closed, then from, to, startEquity, endEquity, deposits, withdrawals, change (without deposits and withdrawals), realized (closed copies, fees and funding included), closed, unrealized and open (copies still open at the end). Editions come out on the 1st of each month for the month just ended. On the test environment (Testnet USDC), full is reserved to the WakeTrades team.
Public
| Method | Path | What it does |
|---|---|---|
GET |
/hello |
Start here: what WakeTrades is, three quick-start steps with their endpoints, the Hyperliquid network, copying (on, pause or halt: the switch for every account), links (docs, OpenAPI, llms.txt, MCP, agent skills, Terms) and version. No session, no Hyperliquid read (Hello) |
GET |
/levels?equity= |
The four exposure levels (prudent, equilibre, risque, advanced) and their rules: size, leaders, total exposure, drawdown alerts, plans, unifiedAccount (required, or xyz_only at advanced), minPracticalBalanceUsd. With equity (USDC) or a session token (your Hyperliquid balance): equity and the recommended level (recommendedLevel, belowAllMinimums, recommendationNote); otherwise these are null. 400 invalid_equity |
GET |
/leader/{address} |
A Hyperliquid trader's card: equity, positions, statistics (stats.type: scalp, day, swing or unknown); stats.d90: the same figures over 90 days, with pnlUsd and pnlPct (perps only); stats.pnl30Usd / pnl30Pct: the 30-day gain on perps. Signed in, each open position (live.open) also has its age, and activity.closed lists the 5 latest closed positions, newest first (coin, side, value, entryPx, exitPx average, pnl after fees, holdMs, closedAt). Without a session, activity has only lastTradeAt when the trader's trades were read in the last 10 minutes, otherwise it is null. statsBusy: true with retryAfter (seconds): no live read was free to compute the card (5 per minute for the whole service); ask again after that delay |
GET |
/leader/{address}/positions π |
The trader's open positions now, in detail: value, entry, mark and liquidation prices, PnL, and age β openedAt (ms, from their last 2,000 trades), or openedBefore when the position is older than those trades; the age comes once GET /leader/{address} has read the trader's trades (kept 10 minutes). Read it before choosing a trader: report figures are month-end. notCopied: true would mark a market WakeTrades never copies; every market listed here is one we copy, so it is false. It does not say whether that position is or will be copied: positions a leader already holds when you start copying are never copied, only the trades they open afterwards. orders: the trader's open orders, newest first β kind (limit, sl stop loss, tp take profit), coin, side (1 buy, β1 sell), reduceOnly, wholePosition (a stop or take profit on the full position), value (USDC), px (trigger price for sl / tp, else limit price), tp and sl (trigger prices of the take profit and stop loss attached to that order, or null), placedAt. Reads not already kept count toward 2 per minute per signed-in account (429 beyond) |
GET |
/teapot |
418 I'm a teapot with a haiku about copy trading. Just for fun |
GET /me
client:address,state,lang,level,leaders,leader_names,wallet_name,agent_address,agent_approved_at,agent_valid_until,telegram_chat_id,telegram_username,trial_started_at,plan_kind,plan_expires_at,paused_reason,tos_accepted_at,tos_version,created_at.status: the copier βstate,level,leaders,orderMode,accountMode(Hyperliquid's mode:default,unifiedAccount,portfolioMarginβ¦;nullbefore activation),notices,trial_ends_at,plan_expires_at,advanced(Advanced settings, defaults included; on the 6-month plan also at other levels, where they are kept but not applied;nullotherwise),advancedRulesActive(how many Advanced settings differ from the defaults;0at other levels),dailyLossUntil(ms while a daily loss limit is in progress, otherwisenull).notices:["standard_account"]while the account isn't a Unified Account (switch withPOST /account/unified);["unified_now"]once an account seen as standard has become unified.POST /notices/dismiss { "id" }hides one for good.equity: the Hyperliquid balance, read at most every 10 minutes; read again right after a payment or a switch to a Unified Account.unified:truewhenstatus.accountModeisunifiedAccountorportfolioMargin; before activation, read from Hyperliquid;nullif unknown.copiesOnHold:{ "held": true, "reasons": ["not_unified", "manual_positions"], "coins": ["BTC"] }.heldistruewhen your leaders' next trades would not be copied now. Computed from what/mealready reads (no extra Hyperliquid read): check it after setup and whenever copies don't appear.renewal:{ "days": 7, "until": 1795000000000, "planKind": "1m", "founderPrice": true }while a paid plan is close to its end (30 days for a 6-month plan, 14 for 3 months, 7 for 1 month), otherwisenull. Renew withGET /pay/preparethenPOST /paybeforeuntil: the new plan starts atuntil, andfounderPrice: truemeans the founder price is kept. Aplan_expiringwebhook event is sent at the start of this period and the day before.
| Reason | Why new copies are on hold | What to do |
|---|---|---|
not_activated |
Sign-up not finished (setup, awaiting_signature, awaiting_telegram) |
Finish Set Up Copying and link a webhook |
paused |
Copying is paused (by you, or because the last alert channel was removed: see client.paused_reason) |
POST /resume |
trial_expired, plan_expired |
The free trial or the plan has ended | Pay a plan (Pay With USDC) |
key_invalid |
The trading key expired or was revoked | Sign a new key (Set Up Copying, steps 2 to 4) |
platform_paused |
WakeTrades paused new copies for everyone (incident) | Wait; open copies stay managed |
no_leaders |
No leader followed | PUT /settings with leaders |
no_margin |
No balance on the Hyperliquid account | Deposit USDC |
not_unified |
Prudent, Balanced, Risky: the account isn't a Unified Account | POST /account/unified with {} |
manual_positions |
Prudent, Balanced, Risky: positions opened outside WakeTrades, listed in coins |
Close them on Hyperliquid |
xyz_not_unified |
Advanced on a standard account: only the xyz markets are held (held stays false) |
POST /account/unified to copy xyz markets too |
Account States
client.state (and status.state):
| State | Meaning |
|---|---|
setup |
Signed in; level or leaders not saved yet |
awaiting_signature |
Settings saved; trading key not signed yet |
awaiting_telegram |
Key confirmed; no alert channel yet (link a webhook or Telegram to start) |
trial |
Copying, 14-day free trial (status.trial_ends_at) |
active |
Copying, plan paid. Paying during the trial switches the state to active at once, while status.trial_ends_at is still in the future: the plan starts when the trial ends (plan_expires_at = end of the trial + the plan's length), so no trial day is lost |
paused_user, paused_auto |
Paused: no new copies, open ones stay managed |
trial_expired, expired |
Trial or plan ended without payment: no new copies, open ones stay managed |
key_invalid |
Trading key expired or revoked: nothing is sent until a new key is signed |
Unified Account
At Prudent, Balanced and Risky, new copies open only on a Hyperliquid Unified Account with no position opened outside WakeTrades. Until then, each new trade of your leaders is skipped (skip: not_unified, or manual_positions for positions opened outside WakeTrades) and an account_blocked event is sent at most once a day. At Advanced, a standard account copies, except the xyz markets (stocks, indices, commodities), which always need a Unified Account (hip3_unified). POST /account/unified with {} switches the account with the trading key, without a wallet signature; it returns { "mode", "unified" } and sends an account_unified event. On Hyperliquid, the USDC moves from Perps to Spot, where it backs every market.
Recommended Level
An account needs a minimum balance to copy, because Hyperliquid has a minimum order size (10 USDC; WakeTrades uses 11 for rounding). Each leader is copied at their position Γ your balance Γ· theirs Γ the level's size Γ· 3; on a small balance, many copies come out under that minimum. Such a copy is not skipped: it opens at 11 USDC, larger than the level's share, so the account takes more risk than its level shows (it is skipped only when the coin's smallest size step would push it above 22 USDC, too_small, or when the exposure cap is reached, cap). Minimum practical balance: 1,100 USDC at Prudent, 550 at Balanced, 300 at Risky (Advanced: 300 with Risky's size) β see why.
recommendedLevel is the most prudent of prudent β equilibre β risque whose minimum your balance covers. Under every minimum, it is risque with belowAllMinimums: true: copies open at the 11 USDC floor whatever the level, and Risky, with the largest share per leader, stays closest to your leaders' proportions. advanced is never recommended. recommendationNote says why in one sentence. The recommendation is only advice: any level can be chosen. With a session token and USDC still in spot on a standard account (a new account's first transfer often lands there), equity is 0: the answer then adds spotUsdc and equitySource: "spot", and recommends on that spot balance. It backs copies once WakeTrades switches the account to unified (POST /account/unified, right after the trading key).
{ "equity": 150, "recommendedLevel": "risque", "belowAllMinimums": true, "recommendationNote": "Your 150 USDC is under every level's minimum balance (β¦)" }
GET /preview
What each level would do with your balance (or ?planned= USDC if the account has no balance yet) and your first leader, plus recommendedLevel, belowAllMinimums and recommendationNote for that balance (Recommended Level):
| Field | Meaning |
|---|---|
equity, walletEquity, planned |
Balance used; your Hyperliquid balance; true if planned was used |
leader, hasStats |
Your first leader; whether their card has statistics (otherwise most fields are null) |
minOrderUsd |
11: Hyperliquid's 10 USDC minimum order plus a rounding margin |
levels.<level>.nextCopyUsd |
Size in USDC of a copy of the leader's median trade at this level, at the trade's full size (the largest size the leader's position reached, adds included: copies follow adds). Never below 11: a proportional copy under the minimum is opened at 11 USDC, not skipped |
levels.<level>.tooSmallPct |
Share (%) of the leader's trades over 30 days whose copy, at the trade's full size, would stay under the minimum at your balance and level. They open at 11 USDC, larger than your level's share: nextCopyUsd: 11 with tooSmallPct: 100 means almost every copy opens at the floor. It falls as the level's size rises (Prudent β₯ Balanced β₯ Risky) |
levels.<level>.exposureX |
Estimated peak total exposure, in times your balance (3 leaders each at their largest position, capped by the level) |
levels.<level>.liquidationDistancePct |
Approximate adverse move (%) that would liquidate the account at exposureX, in cross margin |
levels.<level>.copiesPerMonth, scale |
The leader's trades per month; your copy ratio (your balance Γ· theirs Γ level size Γ· 3) |
levels.<level>.minPracticalBalanceUsd |
Balance from which a typical leader's median trade copies above the minimum at this level: 1,100 (Prudent), 550 (Balanced), 300 (Risky and Advanced by default). See The Four Exposure Levels |
riskAckAboveUsd |
Above this balance, Risky needs riskAck: true |
Warning: Copies Too Small
PUT /settings and POST /agent/verify succeed as usual and may add, at Prudent, Balanced or Risky:
{ "warning": { "code": "copies_too_small", "leader": "0xβ¦", "tooSmallPct": 100, "equity": 65.5, "minOrderUsd": 11, "minPracticalBalanceUsd": 1100, "message": "β¦" } }
It means at least 90% of that leader's trades would copy under the minimum order at your balance: they open at 11 USDC, larger than your level's share, so the account takes more risk than its level shows. Nothing is blocked. Deposit more, pick a larger level, or another leader. It is computed from the same readings as /preview and the leader's card already computed; without a card, no warning.
Suggested Traders
GET /leaders/suggested?level=risque proposes a trader from our latest Monthly Report for the level (advanced uses risque's list), with the report's 90-day figures. The rule, the same on the site, the API and MCP:
- The suggestion of each more prudent level is set aside first, in order: Prudent's, then Balanced's.
- Among the level's #3 to #5 not set aside, the one who opened the most positions in the 30 days before the report is suggested (a tie goes to the better rank). Never #1 or #2. If #3 to #5 were all set aside, the most active of them is suggested anyway. A list shorter than 3, or an edition without this activity figure: the level's top 5 is read from #5 (or the last) up to #1 and the first trader not set aside is suggested.
- One suggestion per level, for every account: three traders of the report in all. You can follow up to 3 leaders (5 at Advanced). The full lists are in the Monthly Report with a paid plan.
countabove 1 is ignored (the answer adds"countLimited": true). Risky strongly recommends 2 leaders: choose the second one yourself.
{ "level": "risque", "list": "risque", "rank": 3, "address": "0xβ¦", "month": "2026-10",
"stats": { "winRatePct": 58, "profitFactor": 1.6, "tradesPerMonth": 24, "medianHoldHours": 9.5 }, "note": "β¦",
"liveCheck": "GET /api/v1/leader/0xβ¦/positions",
"suggestions": [ { "rank": 3, "address": "0xβ¦", "liveCheck": "β¦", "β¦": "β¦" } ] }
The top-level fields are the first suggestion (as before count existed); suggestions lists them all, each with the same fields. The report's figures are month-end: before choosing, read each trader's live positions with liveCheck (GET /leader/{address}/positions), since a trader can hold a large losing position now. The rest of the list comes with a plan.
Order Mode
status.orderMode says how copies enter; PUT /order-mode changes it (MCP set_order_mode).
limit(default for new accounts): a post-only order at the leader's entry price (or the best price on the book if better). Unfilled after 1 minute, it is cancelled and the copy opens at market, unless the price is more than 1% from the leader's entry. If the leader exits before it fills, nothing is copied and alimit_missedevent is sent.market: the copy opens at market right away; skipped (late) if the price is already more than 1% from the leader's entry.
{ "mode": "market" }
Orders already waiting keep their mode.
Advanced Settings
At level advanced (every plan, free trial included), PUT /advanced changes the settings (MCP set_advanced, snake_case names). Fields you leave out keep their value. Every filter and limit below is off by default: until you set one, copying works as before. Size, exposure, alerts, automatic stop, adds and TP/SL: see Set Up Copying.
| Field | Values | Default | What it does |
|---|---|---|---|
markets |
list of crypto, btc, xyz, gold, wti, indexes, no duplicates |
[] (all markets) |
Markets new copies may open on. crypto: any market of Hyperliquid's main perp dex (not xyz); btc: BTC only; xyz: any market of the xyz dex (tokenized stocks, indices, commodities); gold: xyz:GOLD; wti: xyz:CL only (not Brent); indexes: xyz:SP500, xyz:XYZ100, xyz:JP225, xyz:KR200 |
minMarketLeverage |
integer 1 to 50, or null |
null |
Copy only markets whose maximum leverage on Hyperliquid is at least this |
maxLeverage |
integer 1 to 50, or null |
null |
Cap on the leverage set on your copies (otherwise the market's maximum, in cross margin). It changes the margin used, not the size of the copy |
sides |
both, long, short |
both |
Copy only new positions on this side |
copyStopPct |
number 1 to 90, or null |
null |
Your own stop on each new copy: reduce-only, at the entry price βX % (long) or +X % (short) |
dailyLossPct |
number 1 to 50, or null |
null |
When your balance, deposits and withdrawals excluded, falls X % below its first reading of the UTC day, no new copies for 24 hours |
tp1Pct, tp1ClosePct |
number 1 to 1000 or null; 1 to 100 |
null; 50 |
Take profit 1 on each new copy, at a PnL of +X % of the copy (leverage included, as Hyperliquid shows it: at 10Γ, 20 = +2 % price); closes Y % of the copy |
tp2Pct, tp2ClosePct |
number above tp1Pct or null; 1 to 100 |
null; 100 |
Take profit 2; closes Y % of what is left |
slPct, slClosePct |
number 1 to 100 or null; 1 to 100 |
null; 100 |
Your own stop loss on each new copy, at a PnL of βX % of the copy; closes Y % of the copy (100 = all) |
breakEvenAfterTp1 |
boolean | false |
After take profit 1, move the copy's stop to break-even (entry price plus 0.1 % of fees) |
{ "markets": ["btc", "gold"], "minMarketLeverage": 20, "maxLeverage": 5, "sides": "long", "copyStopPct": 8, "dailyLossPct": 10 }
- Which trades open. The ticked
marketscombine with OR (["btc", "gold"]copies BTC and gold);minMarketLeverageandsidesapply on top (AND). These rules decide only which new copies open: adds, reductions and closes of a copy already open are always followed, even if you change the rules afterwards. - Skipped trades. A leader's trade not copied by these rules shows in
GET /orders(and on the stream) as a skip with a stable code:market_filtered,leverage_filtered,side_filteredordaily_loss_limit. maxLeverageis set when the copy opens and kept for its adds.copyStopPct. The stop stays at that price, computed from the copy's first entry, and is resized to the whole copy after adds and reductions. If the leader's copied stop (copyLeaderTpSl) is closer to the entry, the leader's is kept instead. It is capped at 80 % of the distance to liquidation; under 1 %, the trade is skipped (liq_close). If no stop can be placed, the copy is closed right away. Copies already open keep the stop they opened with.dailyLossPct. The day's reference is your balance's first reading of the UTC day; a plan payment is taken out of it (it is not a loss). Deposits and withdrawals since that reading do not count: before the limit applies, WakeTrades reads your Hyperliquid ledger and takes money that came in out of your balance and adds money that left back to it (moves between your perps and spot balances are ignored). If the ledger cannot be read, the limit is not applied on that check and is checked again at the next one, 5 minutes later. When the limit is reached, adaily_loss_limitevent goes to your webhook and Telegram, andstatus.dailyLossUntilgives the end of the 24 hours. Copies already open stay managed: adds, reductions, closes, stops. SettingdailyLossPcttonulllifts a limit in progress.- Your own take profits and stop loss (
tp1Pct,tp2Pct,slPct). Placed on Hyperliquid when the copy opens, as reduce-only trigger orders at the price that gives that PnL % for the copy's leverage; they sit next to your leader's copied stop-loss and take-profit (copyLeaderTpSl) andcopyStopPct: the first one reached runs, and when several stops close the whole copy, the closest is kept. After a partial close the copy keeps following the leader on what is left (its adds, reductions and close), without buying the closed part back. If the part to close, or what would be left, is under Hyperliquid's minimum order, the level closes the whole copy. They apply to copies opened after you save them. - Kept across levels. Your settings stay saved when you switch to another level and apply again when you come back to
advanced.GET /mereturns them instatus.advancedat every level; they apply only atadvanced, sostatus.advancedRulesActive(how many differ from the defaults) is0at other levels.PUT /advancedanswers{ "advanced", "advancedRulesActive" }.GET /levelslists the bounds (levels.advanced.fields) and the market groups (marketGroups).
Account Deletion
GET /account/delete-check π, then POST /account/delete/nonce π and POST /account/delete π with a signed message, like sign-in. Allowed when every open copy has a stop (stops_required otherwise).
Hello
GET /api/v1/hello (MCP: hello) is the first call to make. Public and cheap: no session, no Hyperliquid read.
{
"name": "WakeTrades",
"what": "Non-custodial copy trading on Hyperliquid: we copy the traders you choose onto your own Hyperliquid account, and funds never leave it.",
"quickStart": [
{ "step": "Sign in with your wallet (EIP-191)", "endpoint": "POST /api/v1/session/nonce, then POST /api/v1/session/verify" },
{ "step": "Choose an exposure level, then traders", "endpoint": "GET /api/v1/levels, PUT /api/v1/settings, GET /api/v1/leaders/suggested" },
{ "step": "Sign the trading key (it can trade, never withdraw)", "endpoint": "POST /api/v1/agent, POST /api/v1/agent/approve, POST /api/v1/agent/verify" }
],
"network": "Mainnet",
"copying": "on",
"links": { "docs": "β¦/docs/api/", "openapi": "β¦/openapi.json", "llms": "β¦/llms.txt", "mcp": "β¦/mcp", "skills": "https://github.com/waketrades/hyperliquid-copy-trading-agent-skills", "terms": "β¦/terms" },
"version": "0.1.0"
}
copying is the switch for every account: pause means no new copies for anyone (open ones stay managed), halt means no order at all during an incident. The full flow, webhook and payment included, is in WakeTrades for AI Agents.
Dry Run
Add ?dryRun=true (or "dryRun": true in the body) to rehearse a call with no effect:
PUT /settings: every check of the real call runs, with the same errors (unknown_leader,too_many_leaders,risk_ack_requiredβ¦). The answer is what the call would give:{ "dryRun": true, "client": { β¦ as it would be }, "activeLeaders", "warning"?, "equity", "recommendedLevel", "belowAllMinimums", "recommendationNote" }. Nothing is saved and no event is sent.POST /pay: every check of the real call runs (action, plan and amount, receiver, token, signer, age), plus the balance of the signed source (perps forusdSend, spot forsendAsset:409 insufficient_usdc). The answer is{ "dryRun": true, "ok": true, "plan", "amount", "from", "source", "balanceChecked", "wouldRelay": true }, or the same error the real call would give. Nothing is relayed to Hyperliquid, no plan is applied and nothing is written. Then send the same action withoutdryRun, within its 10 minutes: the real call runs every check again.
MCP: dry_run: true on set_copy_settings and submit_payment.
Idempotency
POST /pay, /agent/approve, /close-all, /close-position, /emergency-stop, /pause, /resume and /account/unified accept an optional Idempotency-Key header: 1 to 255 printable ASCII characters, a UUID for example. Use a new key for each new action, and the same key to retry it.
- First call: runs normally; its answer is kept 24 hours for your account and that key.
- Same key, same request (same method, path and body) within 24 hours: the first answer comes back with the header
Idempotent-Replayed: true, and nothing runs again. A payment is never relayed twice. - Same key, different request:
422 idempotency_key_reused. - Same key while the first call is still running:
409 idempotency_in_progress; retry a few seconds later. - Not kept:
5xxand429answers (retry with the same key, it runs again), and dry runs (dryRunignores the key). - Errors are kept too: a
4xxanswer comes back on every retry with the same key. Once you fix the cause (a new signature, more USDCβ¦), send the corrected request with a new key. - Keys are per account: another wallet can use the same key.
MCP: idempotency_key on submit_payment, submit_trading_key, switch_to_unified_account, pause_copying, resume_copying, close_position, close_all and emergency_stop.
Errors
Every error is { "error": "<code>", "message": "<English text>", "fix": "<what to do next>", "docs": "<URL>" }, sometimes with detail and other fields. fix is one short sentence saying what to do next; docs links to the most useful section of these pages. Codes are stable; messages and fixes may change. MCP tool errors carry the same fields.
{ "error": "stale_signature", "message": "The signed action is older than 10 minutes. Sign a new one.", "fix": "Prepare and sign a new payment, then send it within 10 minutes.", "docs": "https://waketrades.com/docs/api/payments#errors" }
| Status | Codes |
|---|---|
400 |
bad_request (see detail), invalid_idempotency_key, bad_input, invalid_address, invalid_url, https_required, public_host_required, port_not_allowed, unknown_leader, too_many_leaders, advanced_only, invalid_level, invalid_count, invalid_equity, invalid_approval, terms_acceptance_required, no_agent_key, unknown_plan, invalid_payment_action, wrong_amount, wrong_destination, wrong_token, stale_signature, invalid_signature, wrong_signer, payments_closed, invalid_message, invalid_email, invalid_name, leader_not_followed, invalid_wallet_name, unknown_notice, invalid_edition, unknown_level |
401 |
session_required, unknown_account, invalid_nonce, invalid_message, wrong_signer, agent_code_expired |
403 |
banned, origin_not_allowed, account_required, wallet_required, paid_plan_required, view_only, access_required |
404 |
not_found, no_suggestion, no_edition |
409 |
idempotency_in_progress, risk_ack_required, agent_not_registered_yet, activation_required, alert_channel_required, webhook_not_linked, telegram_not_linked, stops_required, insufficient_usdc, key_required |
422 |
webhook_unreachable, idempotency_key_reused |
426 |
upgrade_required (GET /stream without Upgrade: websocket) |
429 |
rate_limited, signup_limit, feedback_limit, too_many_streams (3 open streams per account) |
451 |
geo_blocked (restricted location of the request's IP address, when the location filter is on; it is off today) |
502 |
hyperliquid_refused (reason: no_deposit, too_many_agents, other), switch_failed (Hyperliquid didn't switch the account: switch it in your Hyperliquid settings) |
503 |
idempotency_unavailable (retry later, or without the header), maintenance (copies keep running; retry later), platform_halt (incident: no order is sent, close-all, emergency stop and account deletion included; your positions stay on Hyperliquid with their stops) |