Skip to content

Exchange Collateral

Swap one collateral asset for another within a subaccount. The platform uses current oracle prices to determine the exchange rate.

Endpoint

POST https://papi.synthetix.io/v1/trade

Request

Request Format

{
  "params": {
    "action": "exchangeCollateral",
    "subAccountId": "1867542890123456789",
    "fromSymbol": "ETH",
    "toSymbol": "USDT",
    "fromAmount": "0.5"
  },
  "nonce": 1704067200000,
  "signature": {
    "v": 28,
    "r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
  },
  "expiresAfter": 1704067300
}

Request Parameters

ParameterTypeRequiredDescription
paramsobjectYesParameters object containing method details
params.actionstringYesMust be "exchangeCollateral"
params.subAccountIdstringYesSubaccount identifier
params.fromSymbolstringYesSource collateral asset symbol (e.g., "ETH")
params.toSymbolstringYesDestination collateral asset symbol (e.g., "USDT")
params.fromAmountstringYesAmount of the source asset to exchange, as a decimal string
nonceinteger (uint64)YesPositive integer, incrementing nonce
signatureobjectYesEIP-712 signature object
expiresAfterintegerNoExpiration timestamp in Unix milliseconds (optional)
ParameterTypeRequiredDescription
nonceuint64Yes*Positive integer nonce (must be incrementing and unique per request)
signatureobjectYesEIP-712 signature object
expiresAfteruint64NoUnix milliseconds expiration timestamp (5x rate limit on stale cancels)

:::info Common Parameters These are top-level request parameters. The subAccountId parameter is specified within the params object (see each endpoint's parameter table). :::

:::info SubAccountAction Endpoints Endpoints using SubAccountAction signing (getPositions, getOpenOrders, getOrderHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates, getWithdrawableAmounts, getFeeRate, getSnaxpotEpochTickets) do not require the nonce parameter. Only signature and optional expiresAfter are needed. :::

Response

Success Response

{
  "status": "ok",
  "response": {
    "fromSymbol": "ETH",
    "toSymbol": "USDT",
    "fromAmount": "0.5",
    "toAmount": "1250.00"
  },
  "request_id": "5ccf215d37e3ae6d"
}

Response Fields

FieldTypeDescription
fromSymbolstringSource collateral asset symbol
toSymbolstringDestination collateral asset symbol
fromAmountstringAmount exchanged from the source asset
toAmountstringAmount received in the destination asset

Error Response

{
  "status": "error",
  "error": {
    "message": "collateral price stale: order rejected",
    "code": "COLLATERAL_PRICE_STALE"
  },
  "request_id": "5ccf215d37e3ae6d"
}

Common Errors

Error CodeDescriptionAction
COLLATERAL_PRICE_STALESource asset price exceeds the staleness thresholdWait for fresh oracle prices; do not retry immediately
INSUFFICIENT_MARGINExchange would leave the account under margin requirementsReduce exchange amount or add collateral
INVALID_VALUEAsset symbol is not a recognized collateral typeCheck supported collaterals via POST /v1/info (getCollaterals)

Implementation Notes

  • COLLATERAL_PRICE_STALE is a non-retryable trading rejection (error category Trading), not an internal server error — treat it as a transient condition and wait for oracle prices to refresh before retrying
  • fromAmount must conform to the source asset's QuantityPrecision; query POST /v1/info (getAssets) for the allowed precision
  • Exchange rates are determined by current oracle prices at execution time

Signing

All trading methods are signed using EIP-712. Each successful trading request will contain:

  • A piece of structured data that includes the sender address
  • A signature of the hash of that structured data, signed by the sender

For detailed information on EIP-712 signing, see EIP-712 Signing.

Nonce Management

The nonce system prevents replay attacks and ensures order uniqueness:

  • Use any positive integer as nonce
  • Each nonce must be greater than the previous one (incrementing)
  • Date.now() is a convenient option, not a requirement
  • If nonce conflicts occur, increment by 1 and retry

:::note SubAccountAction Exception SubAccountAction endpoints (getPositions, getOpenOrders, getOrderHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates, getWithdrawableAmounts, getFeeRate, getSnaxpotEpochTickets) do not require a nonce. Only the signature and optional expiresAfter parameters are needed. :::

Error Handling

Error CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes

Related