For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

API value
Basis points
Percentage of order notional

10

1 bp

0.01%

50

5 bp

0.05%

200

20 bp

0.2%

2000

200 bp

2%

Engine
Maximum builder fee
API value

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

  1. Resolve the builder account ID as above, and confirm 100 vUSDC in each engine.

  2. Query subaccounts and use data.primaryAccountID as the approval's accountID.

  3. Set the builder's numeric account ID and the requested fee rate.

  4. 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.

  5. Query GET /api/v1/user/{userAddress}/builders. Check builderID and feeRate in data.spot or data.perps for each engine the application uses.

  6. 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.

EIP-712 signing

Sign account-level actions with the user's master wallet and the following domain:

Domain field
Value

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.

HTTP request field
EIP-712 message field

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

  1. Preserve the documented field order in {type, params}. builder is the last field in its containing order or batch structure, with id before fee.

  2. Omit absent optional fields marked omitempty, and retain required zero or false values.

  3. Encode uint64 values 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.

Engine
Stream
Updated balance

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

  1. Query the builder account balances for the current income view. The REST trade field builderFee and compact WebSocket field bf report the fee on a fill; use them instead of recomputing fees from the approval ceiling.

  2. Compare balance changes over the same interval with expected fee receipts, accounting separately for transfers, trades, and other balance changes.

  3. On disconnection, refresh Spot or Perps account balances and resubscribe. A new snapshot restores the current balance, not the missed transaction history.

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

Symptom
Check

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.

Approve Builder Fee

Last updated