# Set Up Copying

> Choose an exposure level and traders (we suggest one for your level), then sign the WakeTrades trading key (Hyperliquid approveAgent, EIP-712) and accept the Terms. Copying and the 14-day free trial start as soon as an alert channel is linked.

## 1. Choose an Exposure Level, Then Traders

**Which level for your balance?** An account needs a minimum balance to copy, because Hyperliquid has a minimum order size: **1,100 USDC at Prudent, 550 at Balanced, 300 at Risky**. Below it, copies under the minimum open at 11 USDC, larger than the level's share. `GET /api/v1/levels` with your session token (or `?equity=` in USDC) returns `recommendedLevel`: the most prudent level whose minimum your balance covers; under every minimum, `risque` with `belowAllMinimums: true`, since Risky stays closest to your leaders' proportions ([Recommended Level](https://waketrades.com/docs/api/endpoints.md#recommended-level)). It is advice: any level can be saved.

`PUT /api/v1/settings`. During sign-up, send the level first, alone:

```json
{ "level": "equilibre", "lang": "en" }
```

The account stays in `setup` and the answer adds `"next": "GET /leaders/suggested"`. No trader in mind? `GET /api/v1/leaders/suggested?level=equilibre` suggests a trader of our latest [Monthly Report](https://waketrades.com/docs/leaders/monthly-report.md) for that level (`advanced` uses `risque`'s list), with figures from the report over the last 90 days. It is the most active of #3 to #5 on the level's list (most positions opened in the 30 days before the report; never #1 or #2), skipping any trader already suggested for a more prudent level; the exact rule is in [Suggested Traders](https://waketrades.com/docs/api/endpoints.md#suggested-traders). One suggestion per level, for every account; at Risky, where 2 leaders are strongly recommended, choose the second one yourself (the full lists are in the monthly report with a paid plan):

```json
{ "level": "equilibre", "list": "equilibre", "rank": 5, "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": 5, "address": "0x…", "…": "…" } ] }
```

The report's figures are month-end: before choosing, read the trader's open positions now with `liveCheck` (`GET /api/v1/leader/{address}/positions`): a trader can hold a large losing position today. Positions a leader already holds when you start copying are never copied, only their new trades. The rest of the list comes with a plan. `404 no_suggestion` means no report is published yet: choose a trader yourself by address and check it with `GET /api/v1/leader/{address}`. Then send the leaders (the suggested address or your own choice); the next step needs at least one:

```json
{ "leaders": ["0xLEADER…"], "level": "equilibre", "lang": "en" }
```

- `leaders`: Hyperliquid addresses to copy, in order of priority. At most 3 (5 at `advanced`): more gives `400 too_many_leaders`. A list already longer, after a move to a level with a lower maximum, is kept: the first ones are followed, the extra ones wait. At `risque`, at least 2 are strongly recommended (one leader is allowed).
- `level`: `prudent`, `equilibre` (Balanced), `risque` (Risky) or `advanced` (every plan, free trial included). See [The Four Exposure Levels](https://waketrades.com/docs/leaders/risk-levels.md); `GET /api/v1/levels` gives the same rules as JSON.
- `riskAck: true` is required to move to Risky with more than 10,000 USDC on the account (`409 risk_ack_required` otherwise).
- Every leader must have a Hyperliquid account (`unknown_leader`).

Settings, leaders included, can be changed the same way at any time.

**Balance.** Each leader is copied at their position × your balance ÷ theirs × the level's size ÷ 3. A copy under Hyperliquid's minimum order opens at 11 USDC instead of being skipped (skipped only when the coin's smallest size step would make it more than 22 USDC), so on a small balance copies are larger than the level's share. Plan for at least **1,100 USDC at Prudent, 550 at Balanced and 300 at Risky** ([why](https://waketrades.com/docs/leaders/risk-levels.md#minimum-practical-balance)); `GET /api/v1/preview` gives `tooSmallPct` for your balance and first leader, level by level. When at least 90% of a followed leader's trades would open at the floor, the answer (here and in step 4) adds a non-blocking `warning` with `code: "copies_too_small"` ([details](https://waketrades.com/docs/api/endpoints.md#warning-copies-too-small)).

### Advanced Settings

At level `advanced`, `PUT /api/v1/advanced` changes the settings, starting from Risky's. Fields you leave out keep their value.

```json
{ "sizePct": 50, "maxExposureX": 10, "maxOpenPositions": null, "alertsPct": [15, 25], "autoStopPct": 20, "followAdds": true, "copyLeaderTpSl": true }
```

- `sizePct`: size of your copies, in % of the leaders' size (5 to 300; 100 = Risky).
- `maxExposureX`: total exposure cap, in times your balance, or `null` for no cap.
- `maxOpenPositions`: maximum of open copies (integer), or `null` for no limit. `PUT /api/v1/max-positions` sets the same value.
- `alertsPct`: drawdown alerts from the account's highest balance, `[heads-up, alert]`.
- `autoStopPct`: automatic stop: at this drawdown, every copy closes and copying pauses. `null` for none.
- `followAdds`: copy your leaders' adds. `copyLeaderTpSl`: copy their take profit and stop loss.
- `markets`, `minMarketLeverage`, `maxLeverage`, `sides`, `copyStopPct`, `dailyLossPct`: which markets and sides new copies open on, a leverage cap, your own stop on each copy, and a daily loss limit. All off by default: see [Advanced Settings](https://waketrades.com/docs/api/endpoints.md#advanced-settings).
- `tp1Pct` / `tp1ClosePct`, `tp2Pct` / `tp2ClosePct`, `slPct` / `slClosePct`, `breakEvenAfterTp1`: your own take profits and stop loss on each new copy, as a PnL % of the copy (leverage included), each closing the share you choose; after a partial close the copy keeps following the leader on what is left. All off by default.

Advanced is open with every plan, free trial included. `PUT /api/v1/max-positions` at another level answers `400 advanced_only`.

## 2. Get the Trading Key's Address

`POST /api/v1/agent` returns `{ "agentAddress", "agentName": "WakeTrades", "hyperliquidChain": "Mainnet" }`. WakeTrades generates this key on its server; the agent never sees its private key and only authorizes its address. Copy `hyperliquidChain` from this answer into the action and the typed data: `"Mainnet"` on waketrades.com, `"Testnet"` on a test environment.

## 3. Sign the Approval (EIP-712)

The agent signs Hyperliquid's `approveAgent` action with its own wallet. Build the action:

```json
{
  "type": "approveAgent",
  "hyperliquidChain": "Mainnet",
  "signatureChainId": "0xa4b1",
  "agentAddress": "<agentAddress>",
  "agentName": "WakeTrades valid_until <now + 179 days, in ms>",
  "nonce": <now, in ms>
}
```

and sign this typed data (same values):

```json
{
  "domain": { "name": "HyperliquidSignTransaction", "version": "1", "chainId": 42161, "verifyingContract": "0x0000000000000000000000000000000000000000" },
  "primaryType": "HyperliquidTransaction:ApproveAgent",
  "types": {
    "HyperliquidTransaction:ApproveAgent": [
      { "name": "hyperliquidChain", "type": "string" },
      { "name": "agentAddress", "type": "address" },
      { "name": "agentName", "type": "string" },
      { "name": "nonce", "type": "uint64" }
    ]
  },
  "message": { "hyperliquidChain": "Mainnet", "agentAddress": "<agentAddress>", "agentName": "WakeTrades valid_until …", "nonce": … }
}
```

`signatureChainId` is the chain the wallet signs on, and the typed data's `domain.chainId` must be the same number: Hyperliquid rebuilds the domain from `signatureChainId`.

| Network | `hyperliquidChain` | `signatureChainId` | `domain.chainId` |
| --- | --- | --- | --- |
| Mainnet (waketrades.com) | `"Mainnet"` | `"0xa4b1"` (Arbitrum One) | `42161` |
| Testnet | `"Testnet"` | `"0x66eee"` (Arbitrum Sepolia), or `"0xa4b1"` | `421614`, or `42161` |

Any chain id works if both values match; the same rule applies to payments (`GET /pay/prepare?chainId=`). Then send it:

`POST /api/v1/agent/approve` with `{ "action": { … }, "signature": { "r": "0x…", "s": "0x…", "v": 27 } }`

WakeTrades checks that the action authorizes its own key, under its name, on the right network and with a recent nonce, then relays it to Hyperliquid, which checks the signature.

**Python** (`eth-account`):

```python
signed = Account.sign_typed_data(PRIVATE_KEY, full_message=typed_data)   # typed_data as above, with an EIP712Domain type
signature = {"r": f"0x{signed.r:064x}", "s": f"0x{signed.s:064x}", "v": signed.v}   # 64 hex digits each: hex() drops leading zeros
```

**JavaScript** (viem):

```js
import { parseSignature } from "viem";
const sig = parseSignature(await account.signTypedData({ domain, types, primaryType, message }));
const signature = { r: sig.r, s: sig.s, v: Number(sig.v) };
```

**No wallet library**: `signTypedData(typedData)` from the short [@noble/curves example](https://waketrades.com/docs/api/authentication.md#javascript-without-a-wallet-library) returns `{ r, s, v }` directly.

## 4. Accept the Terms and Confirm the Key

`POST /api/v1/agent/verify` with `{ "tosAccepted": true }`.

- By sending `tosAccepted: true`, the agent accepts the [Terms of use](https://waketrades.com/docs/legal/terms) on behalf of the wallet's owner.
- `409 agent_not_registered_yet`: Hyperliquid hasn't registered the key yet. Retry after 10 seconds.
- If a webhook is already linked, copying and the 14-day free trial start now (`"state": "trial"`). Otherwise the state is `awaiting_telegram`: link a webhook next ([Webhooks](https://waketrades.com/docs/api/webhooks.md)) and the trial starts then. A new wallet whose webhook host already had a free trial gets none: the answer carries `"noTrial": "webhook_host_used"` and the state is `trial_expired` (pay to copy, [Pay With USDC](https://waketrades.com/docs/api/payments.md)).
- The answer can include a non-blocking `warning` (`copies_too_small`), as in step 1.

## 5. Switch to a Unified Account

`POST /api/v1/account/unified` with the body `{}`, right after step 4.

- 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.
- WakeTrades switches the account with its trading key: no wallet signature. The answer is `{ "mode": "unifiedAccount", "unified": true }`, and an `account_unified` event is sent. An account already unified is left as is.
- On Hyperliquid, your USDC moves from Perps to Spot, where it backs every market; your balance doesn't change.
- `GET /api/v1/me` shows the result: `unified: true`, `status.accountMode: "unifiedAccount"`. While the account isn't unified, `status.notices` holds `"standard_account"`.
- `409 key_required`: the trading key isn't approved yet (step 4). `502 switch_failed`: Hyperliquid refused; switch it yourself ([Switch to a Unified Account](https://waketrades.com/docs/getting-started/switch-to-unified-account.md)).

## 6. Choose the Order Mode

`status.orderMode` in `GET /api/v1/me` says how copies enter. New accounts start in `limit`: a post-only order at the leader's entry price. 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 first, nothing is copied and a `limit_missed` event is sent. To enter at market right away (skipped only beyond 1% from the leader's entry):

`PUT /api/v1/order-mode` with `{ "mode": "market" }` ([Order Mode](https://waketrades.com/docs/api/endpoints.md#order-mode))

## 7. Read Back: Can Copies Open?

`GET /api/v1/me` → `copiesOnHold`. `{ "held": false, "reasons": [], "coins": [] }` means your leaders' next trades will be copied. Otherwise each reason says what to do: `not_unified` (step 5), `manual_positions` (close the positions listed in `coins`), `paused`, `trial_expired`, `plan_expired`, `key_invalid`, `no_leaders`, `no_margin`, `not_activated`, `platform_paused` ([all reasons](https://waketrades.com/docs/api/endpoints.md#get-me)).

## If Hyperliquid Refuses the Key

`502 hyperliquid_refused` with a `reason`:

| Reason | What to do |
| --- | --- |
| `no_deposit` | The Hyperliquid account has no deposit yet. Deposit USDC, then sign again. |
| `too_many_agents` | The account already has 3 named API wallets. Revoke one on Hyperliquid, then sign again. |
| `other` | See `detail` (Hyperliquid's own message). |

## Renew the Key

The key is valid 180 days. A `key_expiring` event (with `days` left) arrives about once a week during the last 30 days. Repeat steps 2 to 4: the old key keeps trading until Hyperliquid registers the new one.
