Manual REST Signing
Implement Perps order signing without an SDK. For the shorter SDK-based path, use Trading Quickstart. This tutorial covers canonical payloads, EIP-712 signatures, raw HTTP requests, and execution tracking.
Before starting, activate and fund your testnet trading account and register a trading API key. The example below submits a real testnet order; it is not a simulation.
1. Choose an environment
Mainnet
https://mainnet-gw.sodex.dev
wss://mainnet-gw.sodex.dev
286623
Testnet
https://testnet-gw.sodex.dev
wss://testnet-gw.sodex.dev
138565
Spot REST paths start with /api/v1/spot; perpetual REST paths start with /api/v1/perps.
2. Make a public request
Public market-data endpoints do not require a signature.
curl "https://testnet-gw.sodex.dev/api/v1/perps/markets/tickers?symbol=BTC-USD" \
-H "Accept: application/json"Successful REST responses use a common envelope with code, timestamp, and endpoint-specific data. A code value of 0 means the request succeeded.
3. Pick an integration path
For most applications, start with an official SDK. The SDKs implement canonical request serialization, EIP-712 signing, signature prefixes, and nonce coordination.
If you need a custom client, read Authentication & Signing before implementing write requests. In particular:
X-API-Keycontains the registered key name, not a private key or address.X-API-Signcontains the EIP-712 signature; the private key is never sent.X-API-Noncemust be unique for the signing address and remain inside the accepted time window.Use the
spot,futures, oruniversalsigning domain required by the action.
4. Get your account ID and trading symbol
Use the master wallet address for account lookup, not the API key's public address. All commands below use the same testnet environment:
Check code == 0 before reading data.
accountID
data.aid from account state
Identifies the trading account in the signed order. This is not uid or a wallet address.
symbolID
id of the selected object in the symbols response's data array
Identifies the market in the signed order.
symbol
name from that same symbol object
Used by market queries and WebSocket subscriptions. Do not use displayName.
Available margin
data.am (cross) or data.ami (isolated) from account state
Check the margin available for the intended position mode.
Price and quantity rules
tickSize, stepSize, pricePrecision, minQuantity, maxQuantity, minNotional, maxNotional
Choose a price and quantity that satisfy the market's filters before signing.
The state endpoint returns the primary account by default. To trade a sub-account, pass its accountID in the state query and use that account ID consistently in the order and subsequent queries. An unactivated account must be activated before continuing.
See Account State, Symbol Fields, and Order Validation Rules.
5. Sign and submit a limit order
This example places one BUY / LIMIT / GTC order. GTC orders can remain open until filled or canceled. Use a testnet price and quantity you intend to trade; do not copy a production order size.
Install dependencies and save the TypeScript code below as place-order.ts:
The request uses these values:
modifier
1
Normal order
side
1
Buy
type
1
Limit
timeInForce
1
Good till canceled
positionSide
1
BOTH
price, quantity
Decimal strings
Preserve the selected market's precision; do not convert amounts to floating-point numbers.
clOrdID
Generated before submission
Your client order identifier; retain it for reconciliation.
The signed payload is {type: "newOrder", params}, but the HTTP body is only params. Keep the field order shown above. The testnet signing domain is futures with chain ID 138565; the signature is prefixed with 0x01. See Authentication & Signing for the original signing definitions.
Check the submission result
Check the HTTP status and top-level
code. HTTP success alone is insufficient.When the top-level
codeis0, inspect each item indata. A batch can contain individual failures.Match each result by
clOrdID. When itscodeis0, save the returnedorderID; otherwise read itserror.Acceptance is not a fill. Continue with execution tracking below.
Pre-validation can return one error for the whole batch rather than one result per order. Do not assume response length always equals request length.
6. Track order status and fills
Connect to wss://testnet-gw.sodex.dev/ws/perps. Prefer subscribing before submission so that immediately filled orders are not missed. Replace YOUR_MASTER_WALLET_ADDRESS and SYMBOL_NAME_FROM_STEP_4 in each message:
Check the subscription acknowledgement's success field. Use Account Order Updates for state changes and Account Trades for executions. Follow the subscription schema when specifying a sub-account.
NEW
Accepted; it may still be resting on the book.
PARTIALLY_FILLED
Some quantity has executed; some remains.
FILLED
The full order quantity has executed.
CANCELED, EXPIRED
No further execution is expected, but partial fills may already exist. Check trades.
REJECTED
The order was not accepted. Inspect the error before correcting the request.
Recover state with REST
Set SYMBOL to the market name from step 4. Use the account ID from the same step:
An order missing from open orders is not necessarily filled: check history for its orderID or clOrdID, then inspect its trades. Paginate history if the order is outside the returned page. To stop an unfilled GTC order, use Cancel Multiple Orders; signing a cancellation is a separate action.
Handle errors and reconnects
HTTP timeout or connection lost during submission
Treat the outcome as unknown. Query open orders and history using the retained client order ID before submitting again. A fresh nonce does not make a retry idempotent.
An order result has a non-zero code
Read its error, check the market filters and available margin, then correct the request.
WebSocket disconnected
Reconnect, resubscribe, and reconcile open orders, history, and trades through REST. Follow the documented ping/pong rules.
Rate limited
Back off according to the applicable rate limits. Do not repeatedly resend signed orders.
Use a separate API key for each concurrent trading process so that processes do not share a nonce tracker. Never place private keys or signature headers in logs.
Next steps
Authentication & SigningRate LimitsREST APIWebSocket StreamsLast updated