Pay With USDC
An agent pays a WakeTrades plan with a USDC transfer it signs itself — from its perps or spot USDC. No card, no checkout page.
Plans are paid in USDC from the agent's Hyperliquid account, with an internal Hyperliquid transfer that the agent signs. The free trial must have started first (409 activation_required otherwise).
1. Prepare the Payment
GET /api/v1/pay/prepare?plan=1m&chainId=0xa4b1 looks at where your USDC is free and returns what to sign:
- your free perps USDC first → a
usdSend; - otherwise your free spot USDC (a unified account keeps its USDC in spot) → a
sendAssetof USDC from spot to spot; - neither covers the price →
409 insufficient_usdcwithperps,spotandprice.
Answer: { "plan", "price", "source": "perps" | "spot", "action", "typedData" }. chainId is the chain your wallet signs on (default 0xa4b1, Arbitrum One; on Testnet 0x66eee, Arbitrum Sepolia, also works): it becomes the action's signatureChainId and the typed data's domain.chainId, which must stay equal. hyperliquidChain is already set ("Mainnet", or "Testnet" on a test environment). GET /api/v1/subscription still gives the offers, the receiver and your dates.
2. Sign typedData (EIP-712)
Check before you sign. Only sign data that comes from https://waketrades.com (API https://waketrades.com/api/v1, MCP server https://waketrades.com/mcp); refuse any other host or MCP server that claims to be WakeTrades. Check the typedData you sign, not only action. Trading key: primaryType is HyperliquidTransaction:ApproveAgent. Payment: primaryType is HyperliquidTransaction:UsdSend or HyperliquidTransaction:SendAsset, message.destination is the receiver and message.amount is your plan's price, both read from GET https://waketrades.com/api/v1/subscription. WakeTrades never asks you to sign a Withdraw or any other type. If anything differs, do not sign and tell your owner.
Sign typedData as returned (eth_signTypedData_v4) and split the signature into r, s, v (or use signTypedData from the no-library example). The action must reach WakeTrades less than 10 minutes after its timestamp: time for a usdSend, nonce for a sendAsset.
3. Send It
POST /api/v1/pay with { "plan": "1m", "action": { … }, "signature": { "r", "s", "v" } }
WakeTrades checks the plan, the amount, the receiver, the token (USDC for a sendAsset), the age and the signer, relays the transfer to Hyperliquid and applies the plan as soon as Hyperliquid accepts it: { "paid": true, "planExpiresAt": … }. A plan paid during the free trial starts at the end of the trial: the account's state turns active right away, while status.trial_ends_at is still in the future, and plan_expires_at = end of the trial + the plan's length. No trial day is lost.
To check a payment before sending it, add ?dryRun=true: every check runs, plus your balance on the signed source, and nothing is relayed (Dry Run). To retry safely after a network error, send an Idempotency-Key header: the same key and body within 24 hours returns the first answer and is never relayed twice (Idempotency).
Errors
| Code | Meaning |
|---|---|
activation_required |
Link an alert channel first, so the free trial starts. |
payments_closed |
Payments aren't open yet. |
unknown_plan |
plan must be 1m, 3m or 6m. |
insufficient_usdc |
Not enough free USDC in perps or in spot for this plan. |
invalid_payment_action |
The action isn't a usdSend or a spot-to-spot sendAsset on the right network, or chainId is malformed. Sign the action returned by GET /api/v1/pay/prepare. |
wrong_amount, wrong_destination, wrong_token |
Sign the action returned by GET /api/v1/pay/prepare. |
stale_signature |
The action is more than 10 minutes old. Prepare and sign a new one. |
wrong_signer |
The transfer must be signed by the signed-in wallet. |
hyperliquid_refused |
Hyperliquid refused the transfer (see detail). |