Authenticated Endpoints
REST API endpoints requiring signature authentication
All authenticated endpoints require EIP-712, EIP-2612, or canonical-JSON personal_sign signatures depending on the endpoint.
Base URL: https://api.app.hello.trade/api
POST /api/referral/apply
Apply an invite code to grant a wallet app access. Without app access, the wallet cannot authenticate against any other authed write endpoint — see Authentication & Account Model — App Access Gate.
Headers
content-type
application/json
x-signature
viem personal_sign over the canonical-JSON payload below
x-timestamp
The same timestamp value used in the signed payload (Date.now() ms)
x-nonce
The same nonce value used in the signed payload — must be unique per request, [A-Za-z0-9_-]{8,128}
Signed Payload (canonical JSON)
{
"body":{
"code":"HELLO12",
"walletAddress":"0xabc..."
},
"method":"POST",
"nonce":"<unique>",
"path":"/referral/apply",
"timestamp":1715500000000,
"walletAddress":"0xabc..."
}body
The full request body, with keys sorted alphabetically. null for bodyless requests. Bodies must be flat JSON objects — nested objects are not deterministically ordered by this scheme.
method
Literal "POST"
nonce
Matches the x-nonce header
path
Literal "/referral/apply"
timestamp
Matches x-timestamp; ms since epoch; server enforces a ±5 minute window
walletAddress
Lowercased wallet that is applying the code
Top-level keys must appear in alphabetical order with no whitespace; keys inside body must also be sorted alphabetically. The server canonicalizes identically before recovering the signer, so any tampering with body fields invalidates the signature.
Request Body
walletAddress
string
Lowercased wallet address (must match the walletAddress in the signed payload)
code
string
Invite code, [A-Z0-9-]{1,7}. Must match the code field inlined under body in the signed payload.
Response — Success
HTTP status 201 Created. kind is "attributed" for affiliate codes and "system" for admin-minted codes; the "system" branch omits referrerAddress.
Response — Errors
400
{"error":"walletAddress and code are required"}
Malformed body
401
{"error":"Unauthorized: <reason>"}
Signature problem (missing headers, expired timestamp, replay, or signer mismatch)
422
{"error":"ALREADY_REFERRED"}
Wallet has already applied a referral code. Attribution is first-touch and immutable.
422
{"error":"CODE_NOT_FOUND"}
No referral code matches the submitted string
422
{"error":"CODE_REVOKED"}
Code is valid but has been revoked. The affiliate likely rotated it; ask for a current code.
422
{"error":"CODE_EXHAUSTED"}
Code has reached its maxUses limit
422
{"error":"SELF_REFERRAL"}
The signer owns the code they're trying to apply
503
{"error":"Referral service unavailable, please retry"}
Transient transport failure between api-gateway and the referral service. Safe to retry.
504
{"error":"Referral service timed out, please try again later"}
Upstream is reachable but slow. Back off before retrying — tight retry loops can worsen a wedge.
TypeScript example
After a successful apply, re-check GET /api/user/access-status/:walletAddress if you want a positive read before issuing further signed requests.
POST /api/margin/deposit
Deposit collateral using ERC-2612 permit and vault authorization.
Request
amount
string
Deposit amount (human-readable, e.g., "1000.50")
instrument
string | null
Instrument symbol for isolated margin, null for cross margin
marginMode
string
"Cross" or "Isolated"
permitSignature
Object
ERC-2612 permit signature (type 0x05)
depositSignature
Object
Vault deposit authorization signature (type 0x07)
Important Notes:
Requires two signatures: Permit (token approval) and Deposit (vault authorization)
permitSignature.payloadcontains encoded Permit struct (token nonce must be fetched from token contract)depositSignature.payloadcontains encoded Deposit struct (includesmarket,flags,deadline)Cross margin:
instrument: null,marginMode: "Cross", and in the Deposit signaturemarket: 0,flagsbit 0 =0Isolated margin:
instrumentset to the market's symbol,marginMode: "Isolated", and in the Deposit signaturemarket= the instrument ID,flagsbit 0 =1. The collateral lands in that market's isolated margin.
For signature construction, see Signatures - Deposits.
Response
command_id
u64
Command ID for tracking
status
string
Submitted or Rejected
Track deposit completion via DepositMargin execution report on WebSocket.
POST /api/margin/withdrawal
Withdraw collateral.
Request
amount
string
Withdrawal amount (human-readable, e.g., "500.25")
instrument
string | null
Instrument symbol for isolated margin, null for cross margin
marginMode
string
"Cross" or "Isolated"
signature
Object
EIP-712 withdrawal signature (type 0x03)
Important Notes:
signature.payloadcontains encoded Withdrawal struct withowner,amount,market,flags,nonce,deadlineCross margin:
instrument: null,marginMode: "Cross", and in the signaturemarket: 0,flagsbit 0 =0Isolated margin:
instrumentset to the market's symbol,marginMode: "Isolated", and in the signaturemarket= the instrument ID,flagsbit 0 =1. Withdraws from that market's isolated margin; alternatively transfer to cross first and withdraw from there.
For signature construction, see Signatures - Withdrawals.
Response
Track withdrawal completion via WithdrawMargin execution report on WebSocket.
POST /api/margin/transfer
Move collateral between cross margin and a market's isolated margin. No tokens move on- or off-chain — the transfer reallocates collateral within the account.
Request
amount
string
Transfer amount (human-readable, e.g., "250.00")
instrument
string
Instrument symbol of the isolated market
direction
string
"crossToIsolated" or "isolatedToCross"
signature
Object
EIP-712 margin transfer signature (type 0x08)
Important Notes:
signature.payloadcontains the encoded MarginTransfer struct withowner,amount,market,flags,nonce,deadlinemarketin the signature is the instrument ID of the isolated market (both directions)flagsbit 0 carries the source account's margin mode —0forcrossToIsolated,1forisolatedToCross— and must matchdirectioncrossToIsolateddraws from cross withdrawable (free collateral);isolatedToCrossdraws from the market's free isolated margin
For signature construction, see Signatures - Margin Transfers.
Response
Track transfer settlement via TransferMargin execution report on WebSocket. The same operation is also available over the trading WebSocket as a transferMargin message (acked with marginTransferred).
POST /api/update_leverage
Update leverage for an instrument.
Request
leverage
u32
Leverage × 100 (e.g., 1000 = 10x)
instrument
string
Instrument symbol
marginMode
string
"Cross" or "Isolated"
signature
Object
EIP-712 leverage update signature (type 0x04)
Important Notes:
signature.payloadcontains encoded LeverageUpdate struct withaccount,market,leverage,flags,nonce,deadlineflagsbit 0 must matchmarginMode(0= Cross,1= Isolated)Leverage is tracked per margin mode: the same instrument can hold different leverage cross vs isolated
For signature construction, see Signatures - Leverage Updates.
Response
Track leverage update completion via UpdateLeverage execution report on WebSocket.
Common Errors
400
Bad Request (invalid parameters, signature verification failed)
404
Not Found (account not found)
500
Internal Server Error
Error response format:
For detailed error descriptions, see Error Codes.
Last updated