Overview

Endpoint

  • Mainnet REST Endpoint

    • Spot: https://mainnet-gw.sodex.dev/api/v1/spot

    • Perps: https://mainnet-gw.sodex.dev/api/v1/perps

  • Mainnet WebSocket Endpoint

    • Spot: wss://mainnet-gw.sodex.dev/ws/spot

    • Perps: wss://mainnet-gw.sodex.dev/ws/perps

  • Testnet REST Endpoint

    • Spot: https://testnet-gw.sodex.dev/api/v1/spot

    • Perps: https://testnet-gw.sodex.dev/api/v1/perps

  • Testnet WebSocket Endpoint

    • Spot: wss://testnet-gw.sodex.dev/ws/spot

    • Perps: wss://testnet-gw.sodex.dev/ws/perps

Key terminology

The docs overload the word "key" in several ways. This table pins the meanings down once; later sections assume these definitions.

Term
What it is
Example

Master wallet

The EVM wallet that owns the Sodex account. Deposits and addAPIKey / revokeAPIKey must be signed by this wallet.

EVM address 0xAbC...123

Master wallet private key

The 32-byte ECDSA private key of the master wallet. Holding it grants full control of the account, so it should stay offline and be used only for the one-time addAPIKey setup and for revocation.

0x1234...cdef (32 bytes, hex)

API key

A named, revocable signing credential attached to the master account (or a sub-account) via addAPIKey. Each master account can hold up to 5 API keys. API keys are for signing trading actions — they cannot query account data. Using an API key (rather than the master wallet) for day-to-day trading is the recommended workflow.

a row with name="api-key-01", publicKey=0x3d45...8256

API key name

The human-readable string that identifies one API key. Must match ^[0-9a-zA-Z_-]{1,36}$ and cannot be default. Passed in the X-API-Key HTTP header (despite the header's name, the value is the key name, not a public key or private key).

"api-key-01"

API key public key

The EVM address registered for that API key. Stored on-chain when you call addAPIKey and also echoed in query responses.

0x3d4595c8742d0a58173a9963c05755b59a8f8256

API key private key

The 32-byte ECDSA private key whose public address matches the API key's public key. Held by the client; used to sign every request that presents that API key's name in X-API-Key.

0xabcd...7890 (32 bytes, hex)

Which key signs what

Action
Who signs
Which private key

addAPIKey / revokeAPIKey

Master wallet

Master wallet's private key

All other trading actions (e.g. newOrder, cancelOrder, transferAsset)

A registered API key

That API key's private key

Recommended workflow: use the master wallet's private key only to register and revoke API keys. For all normal trading requests, sign with a dedicated API key's private key. This lets you keep the master wallet offline and rotate signing credentials without moving funds.

Header naming caveat — the HTTP header X-API-Key carries the name of the key, not the key value. The corresponding private key is used to produce X-API-Sign; the private key itself is never sent over the wire.

API keys and nonces

API keys

A master account can approve or revoke API keys to sign on behalf of the master account or any of the sub-accounts. Each master account can have at most 5 API keys.

Sodex currently supports EVM addresses as API key public keys. The client holds the API key's private key and uses it to sign each request; the server verifies the signature against the API key's registered public key.

API keys are only used to sign. To query account data associated with a master or sub-account, pass the actual accountID of that account — API keys are not lookup identifiers. See Get account ID for how to retrieve your account ID.

Sodex nonces

Similar to Hyperliquid, on Sodex the 100 highest nonces are stored per signing address. Every new transaction must have a nonce larger than the smallest nonce in this set and must never have been used before.

Nonces are tracked per signing address:

  • For trading actions, this is the API key's public key (EVM address) — the one you registered via addAPIKey.

  • For addAPIKey / revokeAPIKey, this is the master wallet's address, which has its own independent nonce counter.

Nonces must be within (T - 2 days, T + 1 day), where T is the Unix millisecond timestamp on the block of the transaction.

The following steps may help port over an automated strategy from a centralized exchange:

  1. Use a separate API key per trading process. Nonces are tracked per signing address (see above), so two sub-accounts that both sign with the same API key share a single nonce tracker — concurrent strategies on each sub-account will race on the nonce. Create one API key per sub-account to avoid this.

  2. The trading logic tasks send orders and cancels to the batching task.

  3. For each batch of orders or cancels, fetch and increment an atomic counter that ensures a unique nonce for the address. The atomic counter can be fast-forwarded to current Unix milliseconds if needed.

This structure is robust to out-of-order transactions within 2 seconds, which should be sufficient for an automated strategy geographically near an API server.

Typed signature

In Sodex, we use EIP712 for Typed structured data hashing and signing. We use different domains for different actions.

Trading actions

For mainnet use 286623 for domain.chainId, for testnet use 138565 for domain.chainId. For spot actions, use spot for domain.name and for perps actions, futures for domain.name.

After you get the signature bytes sig, append byte 1 before the sig bytes to get typed signature. For example, your signed signature is 0x789a6bcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789ab, the correct typed signature is 0x01789a6bcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789ab.

How to compute payloadHash

payloadHash = Keccak256(json.Marshal(payload))

The payload is a JSON object with two fields:

  • For spot: type is one of "newOrder", "cancelOrder", "transferAsset", "scheduleCancel", "revokeAPIKey", and more.

  • For perps: type is one of "newOrder", "cancelOrder", "updateLeverage", "updateMargin", "updateCollateral" (testnet only), "transferAsset", "scheduleCancel", "revokeAPIKey", and more.

You must use your private key of the master account to sign revokeAPIKey action.

Important rules for producing a correct payloadHash:

  1. Compact JSON — no whitespace or newlines. Use json.Marshal in Go, or JSON.stringify without extra arguments in JavaScript.

  2. Key order must match the Go struct field order — the server verifies signatures by parsing the request body into Go structs and re-marshaling via json.Marshal, which serializes fields in struct definition order. If your JSON keys are in a different order, the hash will differ and signature verification will fail.

    • Refer to the struct definitions in sodex-go-sdk-public for the authoritative field order.

    • For example, PerpsOrderItem fields must appear in this order: clOrdID, modifier, side, type, timeInForce, price, quantity, funds, stopPrice, stopType, triggerType, reduceOnly, positionSide.

  3. DecimalString fields are JSON strings, not numbers — fields typed as DecimalString in the schema (e.g. price, quantity, funds, stopPrice) must be serialized as quoted strings in the signing payload (e.g. "quantity":"0.001", not "quantity":0.001). The HTTP request body uses the same format.

  4. omitempty fields must be omitted when unset — optional pointer fields in the Go struct (those with json:",omitempty") must not appear in the JSON when they have no value. Non-optional fields (e.g. modifier, reduceOnly, positionSide) must always be present, even with zero values.

Example — perps market buy order signing payload:

Note: the HTTP request body contains only the params object (without the type wrapper), using the same field order and types as the signing payload.

End-to-end signing example

Signing a newOrder action with a registered API key, end-to-end.

Prerequisite: you have already called addAPIKey (signed by the master wallet — see Add API Key) and hold the API key's private key locally.

Inputs

Steps

  1. Compute payloadHash as described in How to compute payloadHash.

  2. EIP-712-sign the ExchangeAction{payloadHash, nonce} struct with the API key's private key (0x2222…) under domain {name:"futures", chainId:286623, verifyingContract:0x00…00}.

  3. Prepend byte 0x01 to the 65-byte signature → this is the value of X-API-Sign.

  4. Send the request with X-API-Key set to the name of the API key:

The server looks up the API key named api-key-01 on accountID=12345, recovers the signer address from X-API-Sign, and verifies it equals the API key's registered publicKey (0x3d45…8256).

Common pitfalls

  • Putting the API key's EVM address (0x3d45…8256) in X-API-Keywrong; use the name string.

  • Signing the payload with the master wallet's private key — wrong for trading actions; the server verifies against the API key's registered public key and will reject the signature. (Exception: addAPIKey / revokeAPIKey — those must be signed by the master wallet, since they change the API key set itself.)

  • Forgetting the 0x01 prefix — the server rejects un-typed raw 65-byte signatures.

Get account ID

Account IDs are required to query account data and to sign trading actions. Retrieve them via either of:

Via REST API

The aid field in the response is the account ID. By default this is the primary account; pass ?accountID=<id> to query a specific sub-account. The same endpoint is available under ${SPOT_ENDPOINT} for spot.

See WsPerpsState for the full response shape.

Reference Pages

Go SDK Signing GuideAPI Rate LimitsREST API v1WebSocket API v1

Last updated