Builder Codes in Trading
The term "builder" here does not refer to ValueChain block builders. Builder codes let application builders receive a fee on fills they send on behalf of a user. They are set per-order. The user must approve a maximum builder fee for each builder, and can revoke that approval at any time.
To use builder codes, the user first approves a max fee for the builder account ID. Sign that action with the user's master wallet, not an API key. The builder must hold at least 100 vUSDC in Spot and 100 vUSDC in Perps.
Builder codes currently only apply to fees collected in the quote or collateral asset. They do not apply to the buying side of spot trades; they apply to both sides of perp trades. Builder fees charged can be at most 0.2% on perps and 2% on spot.
After approval, orders may include an optional builder parameter: {"id": number, "fee": number}. id is the builder account ID. fee is the builder fee to charge in tenths of a basis point: a value of 10 means 1 basis point of the order notional is charged to the user and sent to the builder.
Each user can have a maximum of 10 active builder approvals at a time.
Become a builder
Any activated trading account can act as a builder once it holds at least 100 vUSDC in each engine. There is no separate builder registration. The builder ID is that account's numeric account ID.
Read it from Query Subaccounts (data.primaryAccountID) or from Spot or Perps account state (data.aid).
The standalone approval endpoint requires that builder account to exist in both engines and to meet the 100 vUSDC requirement in each. These checks also apply when clearing approval with maxFeeRate: 0. Submit maxFeeRate: 0 to free an approval slot.
Fee units and limits
Both fee and maxFeeRate are integers measured in tenths of a basis point:
10
1 bp
0.01%
50
5 bp
0.05%
200
20 bp
0.2%
2000
200 bp
2%
Spot
2%
2000
Perps
0.2%
200
The approval endpoint accepts maxFeeRate from 0 through 2000, inclusive. Each order specifies its rate in builder.fee. That rate must stay within the user's approved maximum and the engine cap in the table above. A Perps order cannot charge more than 200 even when the approval is 2000.
Integration flow
Resolve the builder account ID as above, and confirm 100 vUSDC in each engine.
Query subaccounts and use
data.primaryAccountIDas the approval'saccountID.Set the builder's numeric account ID and the requested fee rate.
Register a trading API key, then approve the builder with the user's master wallet. Sign these requests separately, or use the combined registration action below.
Query
GET /api/v1/user/{userAddress}/builders. CheckbuilderIDandfeeRateindata.spotordata.perpsfor each engine the application uses.Include the approved builder in the signed order and track execution.
An order carrying an unapproved builder is rejected. For orders without a builder, omit the builder field before signing.
Approval succeeds when both engines accept the request. Queries may lag behind submission. After a timeout, error, or incomplete query result, re-query both engines before retrying with a fresh nonce.
Approval example
Approve a builder with the user's master wallet. Client.from_env() uses Mainnet unless SODEX_NETWORK=testnet. Set SODEX_PRIVATE_KEY to the master wallet private key, SODEX_BUILDER_ID to the builder account ID, and SODEX_BUILDER_FEE_RATE to the maximum fee rate.
Python:
examples/approve_builder_fee.py
EIP-712 signing
Sign account-level actions with the user's master wallet and the following domain:
name
universal
version
1
chainId
The exact uint64 value sent in X-API-Chain
verifyingContract
0x0000000000000000000000000000000000000000
For builder actions, the message field chainID is different from domain chainId: use 286623 for SoDEX Mainnet or 138565 for Testnet, regardless of the wallet's selected network. The SDK example uses the SoDEX network ID for both values. Ordinary AddAPIKey registration has no message-level chainID; it uses the network ID in the domain.
Action types
These type strings are case-sensitive, and field order is part of the signature:
Combined API key registration and approval
To register a key and approve a builder in one action, include builder in POST /api/v1/user/{userAddress}/api-keys and sign the AddAPIKeyWithBuilder structure.
type
keyType (1 for EVM)
builder.id
builderID
builder.fee
maxFeeRate
The remaining message fields follow the type string above. builder and permissions are mutually exclusive within a registration request.
See Authentication & Signing for the complete typed-data objects, including the permissioned-key variant.
Signature bytes and headers
For the account-level actions above, X-API-Sign is the hex encoding of 0x02 || r[32] || s[32] || v[1], where v is 0 or 1. Wallet libraries that return 27 or 28 must normalize the recovery byte before adding the prefix. Send the same nonce in the message and X-API-Nonce, and the domain chain ID in X-API-Chain.
Trading orders use the spot or futures domain and signature prefix 0x01.
Order payload and execution
After approval, include this fragment in the order parameters before computing the payload hash:
Replace 456 with your builder account ID. Spot batches specify builder after orders at the batch level. Perps supports a batch default and per-order overrides. Use a rate within both the approval and the engine cap.
SDK examples: Python
Canonical JSON
Preserve the documented field order in
{type, params}.builderis the last field in its containing order or batch structure, withidbeforefee.Omit absent optional fields marked
omitempty, and retain required zero or false values.Encode
uint64values as unquoted JSON integers with full precision. Use the SDK's canonical serializer for signed orders.
The signature hashes the {type, params} wrapper; the HTTP body contains only params. See payload hashing and the order walkthrough for signing, submission, and order-status tracking.
Check the top-level response code and individual order results. Retain clOrdID and the returned order ID for status queries and reconciliation.
Clear approval
Submit maxFeeRate: 0 and verify removal in both approval arrays. Omit the builder from subsequent orders. Manage existing orders separately through the order-cancellation endpoints.
Fee credits and withdrawals
Builder fees credit in real time to the builder account on the engine that produced the fill. There is no separate claim step. Query that account's balances to see income.
Pass the builder account ID as accountID. Spot total includes locked funds; Perps total is wallet balance.
To send credited funds off-chain, use ordinary Withdrawals: Perps → Spot → ValueChain EVM → external. Trading transferAsset only reaches EVM.
An approval sets a fee ceiling; it is not a payment record. Subscribe to the receiving builder account's Account Updates Stream for live balance changes, not the user's builder-approval list.
Spot
wss://mainnet-gw.sodex.dev/ws/spot
data.B[].t (includes locked funds); l is locked funds.
Perps
wss://mainnet-gw.sodex.dev/ws/perps
data.B[].wb (wallet balance).
Each balance includes coin ID i and name a. Values are decimal strings representing the updated balance, not an amount to add. Only updated assets appear in B; an omitted asset has not necessarily become zero.
Monitor builder balances
Use Node.js 22+, set BUILDER_USER_ADDRESS, BUILDER_ACCOUNT_ID, and ENGINE (spot or perps), save as builder-balances.mjs, and run node builder-balances.mjs. This read-only example prints balance updates without submitting trades.
Reconciliation
Query the builder account balances for the current income view. The REST trade field
builderFeeand compact WebSocket fieldbfreport the fee on a fill; use them instead of recomputing fees from the approval ceiling.Compare balance changes over the same interval with expected fee receipts, accounting separately for transfers, trades, and other balance changes.
accountUpdate does not contain a builder-fee reason, per-credit identifier, or trade ID. It shows the balance effect of credits but cannot by itself prove a one-to-one match between a trade fee and a credit. Keep unexplained differences pending; do not classify every positive balance change as builder income.
Troubleshooting
spot builder USDC balance is insufficient
Builder's Spot balance against the 100 vUSDC eligibility requirement.
perps builder USDC balance is insufficient
Builder's Perps balance against the 100 vUSDC eligibility requirement.
Builder account not found
Builder ID is the trading account ID on this network.
Approval visible in only one engine
Re-query both approval arrays before retrying.
More than 10 builders
A user may hold at most 10 approvals; clear one with maxFeeRate: 0.
Signature recovery or API key lookup error
Signing wallet, primary type, field order, chain IDs, signature encoding, and registered API key name.
Builder-enabled order rejected
Approval exists for the relevant engine, requested fee is within the approval and the engine cap (Spot 2%, Perps 0.2%), and builder was included before signing.
Last updated