Appearance
Perpetuals API (Orderly)
All under /api/defi/orderly. Controller: bz-backend/controllers/defi/orderlyController.js.
Blazpay is an Orderly Network client. It manages the account lifecycle and the ed25519 request key; Orderly provides the order book, matching, settlement and liquidation.
Product page: perpetuals.
Account lifecycle
| Method | Path | Purpose |
|---|---|---|
GET | /defi/orderly/account-exits/:walletAddress | Does an Orderly account exist for this wallet? (typo for "exists" is in the route) |
GET | /defi/orderly/getNonce/:walletAddress | Registration nonce from Orderly |
POST | /defi/orderly/register/account | Register the account after the user signs |
POST | /defi/orderly/add-orderly-key | Generate and store the ed25519 request key |
The ed25519 key
Orderly requires a separate keypair for signing API requests, distinct from the wallet key.
@noble/ed25519 generates the pair
bs58 encodes it
utils/kms.js encrypts the private half → models/orderlyAccount.js
getOrderlyKey(walletAddress) decrypts on demand
utils/orderlySigner.js → signAndSendRequest(accountId, privateKey, url, …)This is the one place Blazpay custodies a signing key
It is an API key scoped to Orderly — it cannot move funds out of the user's wallet, and Orderly's withdrawal flow requires a fresh wallet signature. But it is a key the platform holds, encrypted at rest via AWS_KEY_ID_KMS. Treat models/orderlyAccount.js as sensitive data.
Orders
| Method | Path | Purpose |
|---|---|---|
POST | /defi/orderly/limit-order | Create a limit order |
POST | /defi/orderly/tp-sl-order | Create a take-profit / stop-loss order |
PUT | /defi/orderly/limit-order | Edit an order |
POST | /defi/orderly/limit-order/delete | Cancel an order |
GET | /defi/orderly/orders | The user's limit orders (getUsersLimitOrders) |
GET | /defi/orderly/getOrders | Orders (getOrders) |
POST /defi/orderly/limit-order
| Field | Required | Notes |
|---|---|---|
price | yes | Rejected with 400 if missing |
quantity | yes | Rejected with 400 if missing |
symbol | yes | e.g. PERP_ETH_USDC |
leverage | — | Applied to the account before the order |
walletAddress | yes | Resolves the Orderly account |
side | — | Defaults to "BUY" |
Before submitting, the controller:
- Loads the account (
getExitingAccount) and decrypts the Orderly key. - Fetches
https://api-evm.orderly.org/v1/public/info/{symbol}and derives decimal places frombase_tick. - Calls
setLeverageAccount(leverage, account, orderlyPrivateKey). - Signs and posts to
${Orderly.publicUrl}order.
Tick-size rounding is not optional
Orderly rejects orders that violate tick size. getDecimalPlaces(filterSize.base_tick) is why quantity has to be rounded before submission — skipping it produces an opaque upstream rejection.
Leverage is account-level, not per-order
Orderly's model applies leverage to the account. setLeverageAccount is therefore called on every order, which means placing an order at a different leverage changes it for the whole account.
Positions
| Method | Path | Purpose |
|---|---|---|
GET | /defi/orderly/getPositions/:walletAddress | Open positions |
POST | /defi/orderly/close-position | Close a position |
POST | /defi/orderly/set-leverage | Set account leverage |
Withdrawal
| Method | Path | Purpose |
|---|---|---|
GET | /defi/orderly/get-available-withdraw/:walletAddress | Withdrawable balance (getOrderlyHodlings) |
POST | /defi/orderly/request-withdraw | Submit a withdrawal request |
Data model
| Collection | Contents |
|---|---|
models/orderlyAccount.js | account_id, the KMS-encrypted ed25519 key, wallet mapping |
models/limitOrder.js | Order records |
models/limitOrder.js is shared
It backs both perp orders and the unshipped spot limit-order product. Any query that does not filter by source mixes the two. See limit orders.
Configuration
Orderly in bz-backend/utils/constants.js holds publicUrl and related endpoints. The public info endpoint is https://api-evm.orderly.org/v1/public/info/{symbol}.
Helpers in utils/helpers.js: getDecimalPlaces, getExitingAccount, getOrderlyKey, setLeverageAccount, tInverse, sendResponse.
Frontend
| Surface | File |
|---|---|
| Trading page | defi-dex/src/pages/defi/perpetual.tsx (~710 lines) |
| Order history | defi-dex/src/pages/defi/PerpetualTransactions.tsx → /defi/perpetual-transaction |
| SEO landing page | /perpetuals via src/data/featureSeo.mjs |
Failure modes
| Symptom | Cause |
|---|---|
| 400 "verify you are providing all the required details" | price or quantity missing |
| Opaque upstream rejection | Tick-size violation, or a symbol Orderly does not list |
| Leverage changed unexpectedly | It is account-level; another order set it |
| Account not found | No registration, or add-orderly-key never ran |
| Cannot decrypt the Orderly key | KMS misconfiguration (AWS_KEY_ID_KMS) |
| Everything fails at once | Orderly outage — Blazpay has no fallback venue for perps |
Not covered
- No BlazAI intent. The agent cannot open or manage a perp position; this is a deliberate scope decision.
- Perp collateral does not appear in portfolio totals — it sits inside Orderly, and the portfolio is Zerion-backed wallet data.
- Deposits happen through Orderly's own contract flow rather than a Blazpay endpoint.