Account API#
GET /account/balance - Account Balance#
Retrieves the total account equity, perp position notional value, position mode, and Token asset details for the master account or a specified sub-account.
For collateral tokens, accAvgPx, spotUpl, spotUplRatio, and entryCost return empty strings.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| vaultAddress | String | No | Sub-account address. Omit to query the master account; provide it to query a specified sub-account. |
Request Examples
GET /api/v5/exchangeos/account/balance
GET /api/v5/exchangeos/account/balance?vaultAddress=0x6d1a19e1e03b83163fb38d7336b58875e71c50c2Envelope Response Fields
| Field | Type | Description |
|---|---|---|
| code | String | API response code. "0" indicates success. |
| msg | String | Response message. Empty on success. |
| data | Array | Account balance data. |
data[] Fields
| Field | Type | Description |
|---|---|---|
| totalEq | String | Total account equity, including only Tokens where pointFlag=false. |
| notionalUsd | String | Sum of the absolute notional values of all established perp positions, in USD. |
| positionMode | String | Position mode: oneWay or hedge. |
| block_height | String | On-chain block height corresponding to the query result. |
| block_timestamp | String | On-chain block time corresponding to the query result, as a Unix timestamp in milliseconds. |
| details | Array | Asset details for each Token. |
details[] Fields
| Field | Type | Description |
|---|---|---|
| tokenId | String | Token ID. |
| collateralEnabled | Boolean | Whether the Token is enabled as collateral. |
| eq | String | Token equity. |
| eqUsd | String | USD value of Token equity. |
| isoEq | String | Isolated equity. Returns an empty string when not applicable. |
| cashBal | String | Cash balance. |
| availBal | String | Available balance. |
| availEq | String | Available equity. Returns an empty string when not applicable. |
| frozenMgn | String | Frozen margin. |
| spotFrozen | String | Frozen Spot amount. |
| perpFrozen | String | Frozen perp margin. Returns an empty string when not applicable. |
| predFrozen | String | Frozen Prediction margin. Returns an empty string when not applicable. |
| mmr | String | Maintenance margin requirement. Returns an empty string when not applicable. |
| mgnRatio | String | Margin ratio. Returns an empty string when not applicable. |
| frozenMgnRatio | String | Frozen margin ratio. Returns an empty string when not applicable. |
| accAvgPx | String | Spot accumulated average position price. Returns an empty string for collateral Tokens. |
| spotUpl | String | Spot unrealized PnL. Returns an empty string for collateral Tokens. |
| spotUplRatio | String | Spot unrealized PnL ratio. Returns an empty string for collateral Tokens. |
| entryCost | String | Spot position cost. Returns an empty string for collateral Tokens. |
| upl | String | perp unrealized PnL. Returns an empty string when not applicable. |
| isoUpl | String | Isolated unrealized PnL. Returns an empty string when not applicable. |
| lastPx | String | Latest price. |
| tokenPx | String | Token price. |
| totalLever | String | Total leverage. Returns an empty string when not applicable. |
Calculation Basis
totalEq
= Σ details[].eqUsd, including only Tokens where pointFlag=false
frozenMgn
= spotFrozen + perpFrozen + predFrozen
notionalUsd
= Σ abs(positionValue of all established perp positions)Return Rules
- A valid numeric value of zero is returned as
"0". - Fields that are not applicable are returned as
"". - Margin-related fields for non-collateral Tokens return
"". - Equity for live trading and points trading must not be combined.
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"totalEq": "110060.000000",
"notionalUsd": "9891.086264",
"positionMode": "oneWay",
"block_height": "12092417",
"block_timestamp": "1785218400074",
"details": [
{
"tokenId": "0",
"collateralEnabled": true,
"eq": "100060.000000",
"eqUsd": "100060.000000",
"isoEq": "0.000000",
"cashBal": "100000.000000",
"availBal": "98712.000000",
"availEq": "98712.000000",
"frozenMgn": "1288.000000",
"spotFrozen": "0.000000",
"perpFrozen": "1288.000000",
"mmr": "43.500000",
"mgnRatio": "0.000435",
"frozenMgnRatio": "0.012872",
"accAvgPx": "",
"spotUpl": "",
"spotUplRatio": "",
"entryCost": "",
"upl": "60.000000",
"isoUpl": "0.000000",
"lastPx": "1.000000",
"tokenPx": "1.000000",
"totalLever": "0.086948"
},
{
"tokenId": "3",
"collateralEnabled": false,
"eq": "0.125000",
"eqUsd": "10000.000000",
"isoEq": "",
"cashBal": "0.125000",
"availBal": "0.100000",
"availEq": "",
"frozenMgn": "0.025000",
"spotFrozen": "0.025000",
"perpFrozen": "",
"predFrozen": "0",
"mmr": "",
"mgnRatio": "",
"frozenMgnRatio": "",
"accAvgPx": "60000.000000",
"spotUpl": "2500.000000",
"spotUplRatio": "0.333333",
"entryCost": "7500.000000",
"upl": "",
"isoUpl": "",
"lastPx": "80000.000000",
"tokenPx": "80000.000000",
"totalLever": ""
}
]
}
]
}
GET /account/positions - Positions#
Retrieves perp positions for the master account or a specified sub-account. Spot does not create positions.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| assetId | String | No | perp instrument ID. Omit to return all positions. |
| vaultAddress | String | No | Sub-account address. Omit to query the master account. |
Request Examples
GET /api/v5/exchangeos/account/positions
GET /api/v5/exchangeos/account/positions?assetId=602
GET /api/v5/exchangeos/account/positions?assetId=602&vaultAddress=0x6d1a19e1e03b83163fb38d7336b58875e71c50c2Response Fields
| Field | Type | Description |
|---|---|---|
| block_height | String | On-chain block height corresponding to the query result. |
| block_timestamp | String | On-chain block time corresponding to the query result, as a Unix timestamp in milliseconds. |
| assetId | String | Instrument ID. |
| assetStatus | String | Instrument status. |
| positionSide | String | Position side: net, long, or short. |
| marginMode | String | Margin mode: cross or isolated. |
| leverage | String | Current position leverage. |
| pos | String | Position size. Short positions use a negative value. |
| avgPx | String | Average entry price. |
| markPx | String | Mark price. |
| positionValue | String | Position notional value. |
| upl | String | Unrealized PnL. |
| uplRatio | String | Unrealized PnL ratio. |
| liqPx | String | Estimated liquidation price. |
| imr | String | Initial margin rate. |
| margin | String | Position margin. |
| mmr | String | Maintenance margin requirement. |
| mgnRatio | String | Margin ratio. |
| realizedPnl | String | Realized PnL. |
| fee | String | Trading fee. |
| fundingFee | String | Funding fee. |
| tradeId | String | Most recent trade ID. |
| closeOrderAlgo | Array | Closing TPSL orders associated with the position. |
| > oid | String | Order ID. |
| > assetId | String | Instrument ID. |
| > assetStatus | String | Instrument status. |
| > side | String | Order side: buy or sell. |
| > positionSide | String | Position side being reduced. |
| > marginMode | String | Margin mode. |
| > price | String | Order price. |
| > size | String | Order size. |
| > reduceOnly | Boolean | Whether the order is Reduce-Only. |
| > triggerPx | String | Trigger price. |
| > triggerPriceType | String | Trigger price type: mark or index. |
| > triggerCond | String | Trigger condition: Gte or Lte. |
| > isMarket | Boolean | Whether the order executes at market after triggering. |
| > tpsl | String | TPSL type: tp or sl. |
| > parentOrderId | String | Parent order ID. Empty when no parent order exists. |
| > isActive | Boolean | Whether the order is active. |
| > tpLimit | Boolean | Whether the order is a TP Limit order. |
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"block_height": "12092417",
"block_timestamp": "1785218400074",
"assetId": "602",
"assetStatus": "normal",
"positionSide": "long",
"marginMode": "isolated",
"leverage": "20",
"pos": "1.500",
"avgPx": "3000.000",
"markPx": "3020.000",
"positionValue": "4530.000",
"upl": "30.000",
"uplRatio": "0.132450",
"liqPx": "2864.100",
"imr": "",
"margin": "226.500000",
"mmr": "22.650",
"mgnRatio": "0.088304",
"realizedPnl": "-2.265",
"fee": "-2.265",
"fundingFee": "0.000",
"tradeId": "776",
"closeOrderAlgo": [
{
"oid": "32733862",
"assetId": "602",
"assetStatus": "normal",
"side": "sell",
"positionSide": "long",
"marginMode": "isolated",
"price": "0",
"size": "0",
"reduceOnly": true,
"triggerPx": "3200.000",
"triggerPriceType": "mark",
"triggerCond": "Gte",
"isMarket": true,
"tpsl": "tp",
"parentOrderId": "",
"isActive": true,
"tpLimit": false
}
]
},
{
"assetId": "602",
"assetStatus": "normal",
"positionSide": "short",
"marginMode": "isolated",
"leverage": "10",
"pos": "-2.000",
"avgPx": "3100.000",
"markPx": "3020.000",
"positionValue": "6040.000",
"upl": "160.000",
"uplRatio": "0.258065",
"liqPx": "3394.900",
"imr": "",
"margin": "620.000000",
"mmr": "30.200",
"mgnRatio": "0.038718",
"realizedPnl": "-3.100",
"fee": "-3.100",
"fundingFee": "0.000",
"tradeId": "777",
"closeOrderAlgo": [
{
"oid": "32733863",
"assetId": "602",
"assetStatus": "normal",
"side": "buy",
"positionSide": "short",
"marginMode": "isolated",
"price": "0",
"size": "0",
"reduceOnly": true,
"triggerPx": "3250.000",
"triggerPriceType": "mark",
"triggerCond": "Gte",
"isMarket": true,
"tpsl": "sl",
"parentOrderId": "",
"isActive": true,
"tpLimit": false
}
]
}
]
}
GET /account/max-size - Maximum Order Size#
Retrieves the maximum buy size, maximum sell size, available funds, and closable position size for a specified instrument and account. Supports querying the closable size in hedge mode.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| assetId | String | Yes | perp instrument ID. |
| price | String | No | Price used to calculate the maximum opening size. |
| leverage | String | No | Leverage used to calculate the maximum opening size. |
| reduceOnly | Boolean | No | Whether to query the maximum Reduce-Only order size. |
| vaultAddress | String | No | Sub-account address. Omit to query the master account. |
Request Example: Maximum Opening Size
{
"method": "GET",
"path": "/api/v5/exchangeos/account/max-size",
"query": {
"assetId": "102",
"price": "95000",
"leverage": "10"
}
}
Request Example: Maximum Reduce-Only Size
{
"method": "GET",
"path": "/api/v5/exchangeos/account/max-size",
"query": {
"assetId": "102",
"reduceOnly": true
}
}
Request Example: Sub-account Query
{
"method": "GET",
"path": "/api/v5/exchangeos/account/max-size",
"query": {
"assetId": "102",
"price": "95000",
"leverage": "10",
"vaultAddress": "0x6d1a19e1e03b83163fb38d7336b58875e71c50c2"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| assetId | String | Instrument ID. |
| maxBuySz | String | Maximum buy size. |
| maxSellSz | String | Maximum sell size. |
| avail | String | Available funds. |
| longAvailPos | String | Available long-position size to close. Returns an empty string when not applicable. |
| shortAvailPos | String | Available short-position size to close. Returns an empty string when not applicable. |
Response Example: oneWay Opening Query
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"maxBuySz": "0.42",
"maxSellSz": "0.58",
"avail": "667.09",
"longAvailPos": "",
"shortAvailPos": ""
}
]
}
Response Example: hedge With reduceOnly=true
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"maxBuySz": "0.20",
"maxSellSz": "0.50",
"avail": "667.09",
"longAvailPos": "0.50",
"shortAvailPos": "0.20"
}
]
}
GET /account/position-tiers - Effective User Position Tiers#
perp only. Requires OK-ACCESS-* authentication. Returns the effective tier for the current account and specified contract, including function parameters and the derived limit table. The structure is the same as public GET /market/position-tiers.
Effective Tier Resolution Rules
- The system looks up the tier role
roleIdbound to the user address. - It looks up the special tier configured for the contract and
roleId. - If a matching special tier is found, it is used. If the user is not bound to a role, or no special tier is configured for that contract and role, the contract default tier is used.
Accounts bound to special tier roles, such as MM or VIP, must use this endpoint to calculate opening limits and rates instead of using the public default tier.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| assetId | String | Yes | perp instrument ID. |
| vaultAddress | String | No | Sub-account address. Omit to query the master account. |
Request Example
GET /api/v5/exchangeos/account/position-tiers?assetId=102Response Fields
Formulas and behavior are the same as GET /market/position-tiers.
| Field | Type | Description |
|---|---|---|
| assetId | String | Instrument ID. |
| positionTierId | String | Effective position tier ID. |
| roleId | String | Effective tier role ID. |
| roleName | String | Effective tier role name. |
| basePositionValue0 | String | Reference position value of the margin-rate curve. |
| baseMMR0 | String | Base maintenance margin rate. |
| baseIMR0 | String | Base initial margin rate. |
| mmrChangeRate | String | Maintenance margin rate change rate. |
| imrChangeRate | String | Initial margin rate change rate. |
| maxPositionValue | String | Maximum position value. |
| imrCurvePosValueGrid | String | Position-value grid of the initial margin-rate curve. |
| maxLeverage | String | Maximum leverage. |
| tiers | Array | Mapping between leverage and maximum allowed position value. |
| > leverage | String | Leverage value. |
| > maxPositionAllowed | String | Maximum allowed position value at this leverage. |
Response Example: MM Role With a Matching Special Tier
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"positionTierId": "16",
"roleId": "1",
"roleName": "MM",
"basePositionValue0": "100000",
"baseMMR0": "0.004",
"baseIMR0": "0.008",
"mmrChangeRate": "0.0002",
"imrChangeRate": "0.0004",
"maxPositionValue": "10000000",
"imrCurvePosValueGrid": "10000",
"maxLeverage": "125",
"tiers": [
{
"leverage": "125",
"maxPositionAllowed": "100000"
},
{
"leverage": "50",
"maxPositionAllowed": "3100000"
},
{
"leverage": "1",
"maxPositionAllowed": "10000000"
}
]
}
]
}
POST /account/set-leverage - Set Leverage#
Sets leverage for a specified perp instrument. The target account is determined by user and the optional vaultAddress.
This endpoint sets leverage only; it does not switch between cross and isolated. The current margin mode is determined by the on-chain account configuration.
General Leverage and Margin-Mode Rules
- Margin mode is configured by account and
assetId. - For the same account and
assetId, onlycrossorisolatedcan be used at a time; the two modes cannot coexist. - In hedge mode, long cannot use
crosswhile short usesisolated. - A configured leverage value persists and is not changed by closing positions or other trading operations. It remains configured even with no positions and no open orders, and can be changed only by another leverage-setting request.
positionSideis optional and nullable. Valid non-empty values arenet,long, andshort.- In oneWay mode or hedge + cross mode, omit
positionSideor passnull. - In hedge + isolated mode, explicitly pass
longorshort.
Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | Object | Yes | Business action object included in the EIP-712 signature. |
| > type | String | Yes | Fixed as updateLeverage. |
| > assetId | String | Yes | perp instrument ID. |
| > positionSide | String | Conditionally required | net, long, short, or null. Must be long or short in hedge + isolated mode. |
| > leverage | String | Yes | Target leverage. Must be an integer greater than or equal to 1. |
| nonce | Number | Yes | Current timestamp in milliseconds, used for signing and replay protection. |
| user | String | Yes | Master account address. |
| vaultAddress | String | No | Sub-account address. When provided, the specified sub-account is updated. |
| signature | Object | Yes | EIP-712 ECDSA signature. |
| > Ecdsa | Object | Yes | ECDSA signature object. |
| >> r | String | Yes | Signature r value prefixed with 0x. |
| >> s | String | Yes | Signature s value prefixed with 0x. |
| >> v | Number | Yes | Signature recovery value: 0 or 1. |
positionSide Rules
In hedge + isolated mode, each updateLeverage action can modify only one side, either long or short. It cannot modify both sides in a single action.
To modify both long and short, submit two independent requests with different nonce values. The two on-chain transactions execute independently and are not atomic.
Validation and Behavior
leveragemust be an integer greater than or equal to1.- The maximum permitted leverage is dynamically determined by the current position tier, position value, and opening-order value.
- oneWay mode does not accept
longorshort. - hedge + cross does not permit an update to only
longorshort. - hedge + isolated requires an explicit
longorshort. - Updating one side in hedge + isolated mode does not affect the leverage of the other side.
- Increasing leverage does not perform an additional margin validation.
- Decreasing leverage requires sufficient margin at the target leverage.
- The request is rejected if the number of open orders exceeds the limit allowed for leverage adjustment. Cancel some open orders first.
- A request with the same leverage as the current value for the target configuration is treated as a no-op.
- Leverage configuration does not depend on an existing position and remains stored even if no position exists.
Request Example: oneWay With cross or isolated
positionSide is omitted:
{
"action": {
"type": "updateLeverage",
"assetId": "102",
"leverage": "10"
},
"nonce": 1708930000000,
"user": "0x9a8f...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Request Example: hedge With cross
Long and short share leverage, so positionSide is also omitted:
{
"action": {
"type": "updateLeverage",
"assetId": "102",
"leverage": "8"
},
"nonce": 1708930000001,
"user": "0x9a8f...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Request Example: hedge With isolated, Update long
{
"action": {
"type": "updateLeverage",
"assetId": "102",
"positionSide": "long",
"leverage": "10"
},
"nonce": 1708930000002,
"user": "0x9a8f...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Request Example: hedge With isolated, Update short
{
"action": {
"type": "updateLeverage",
"assetId": "102",
"positionSide": "short",
"leverage": "5"
},
"nonce": 1708930000003,
"user": "0x9a8f...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"txHash": "0x..."
}
]
}
POST /account/set-margin-mode - Set Margin Mode#
Sets the margin mode for a specified perp instrument, switching between cross and isolated.
This is a write operation. The request action is the EIP-712 signing object and must use canonical Action fields.
The configuration scope is:
target account × assetIdMaster accounts and sub-accounts maintain margin mode independently. Include vaultAddress in the signed envelope when operating on a sub-account.
This endpoint applies only to perp, does not apply to Spot, and does not accept positionSide. In hedge mode, the long and short sides must switch margin mode together.
Margin-Mode Rules
- Only one margin mode can exist for the same account and
assetId. - Cross and isolated positions cannot coexist for the same account and
assetId. - In oneWay mode, the
netposition for theassetIdswitches as a whole. - In hedge mode,
longandshortswitch together. - Switching only
longor onlyshortis not allowed. positionSidemust not be included inaction.- Master-account and sub-account configurations are independent.
- Partially closed positions can still switch margin mode.
- The switch updates the position
marginModedirectly; it does not close and reopen positions. - Setting the target mode to the current mode is accepted as an idempotent request and leaves the configuration unchanged.
- An idempotent request does not guarantee an
exchangeos-setting-updatesevent. - If the switch fails, the original
marginMode, positions, leverage, and funds remain unchanged.
Preconditions
Before switching, the system checks:
assetIdmust exist and be a valid perp instrument.- The target
marginModemust be supported by the instrument. - An isolated-only instrument cannot switch to
cross. - The same
assetIdmust not have any pending orders, including regular resting orders, Trigger Orders, Order-Attached TPSL, and Position-Attached TPSL. - Mark Price must be available.
- Margin after the switch must satisfy risk-control requirements.
- When switching hedge + isolated to cross, the long and short leverage values must satisfy the merge rules.
If any condition is not met, the switch fails and the original configuration remains unchanged.
Leverage Inheritance Rules
oneWay
- cross to isolated: retains the current net leverage.
- isolated to cross: retains the current net leverage.
hedge + cross to isolated
- Long and short switch to isolated together.
- Both long and short initially inherit the shared cross leverage.
- After the switch, long and short leverage can be adjusted independently through
POST /account/set-leverage.
hedge + isolated to cross
- If long and short both have positions with different leverage, the switch fails.
- If long and short both have positions with the same leverage, the resulting cross mode uses that shared leverage.
- If only long has a position, the resulting shared leverage uses the long leverage.
- If only short has a position, the resulting shared leverage uses the short leverage.
- If neither long nor short has a position, the shared leverage uses the currently effective account-level setting for the
assetId.
Margin Validation: cross to isolated
The system transfers sufficient funds from the cross balance to isolated positions.
Initial margin required for each position:
positionIM
= abs(pos) × avgPx ÷ leverageAdditional amount required for negative unrealized PnL:
negativeUplBuffer
= abs(min(0, upl))Required transfer for one position:
requiredTransfer
= positionIM + negativeUplBufferIn hedge mode, if both long and short positions exist, calculate each separately and add them together:
requiredTransferTotal
= Σ(positionIM + negativeUplBuffer)Validation condition:
coinMaxTransfer >= requiredTransferTotalThe switch is permitted at equality:
coinMaxTransfer == requiredTransferTotalThe request is rejected when:
coinMaxTransfer < requiredTransferTotalAfter a successful switch:
- The system transfers
requiredTransferTotalfrom the cross balance to the relevant isolated positions. - The position
marginModeis updated toisolated. - The isolated position balances increase by the transferred amount.
Margin Validation: isolated to cross
The system transfers isolated position balances back to cross and reruns risk validation using the hypothetical post-switch account state.
Validation condition:
coinEquityAfter >= coinPerpPosFrozenMarginAfterWhere:
coinEquityAfteris the collateral-token equity after hypothetically converting isolated positions to cross.coinPerpPosFrozenMarginAfteris the margin required by all cross perp positions after the hypothetical switch.
The switch is permitted at equality:
coinEquityAfter == coinPerpPosFrozenMarginAfterThe request is rejected when:
coinEquityAfter < coinPerpPosFrozenMarginAfterAfter a successful switch:
- The relevant isolated position
posIsoPerpBalanceis transferred back to cross. - The position
marginModeis updated tocross. - The original isolated position balance is reset to zero.
- Cross margin jointly bears position risk after the switch.
Precision and Boundary Rules
- Margin validation uses the internal fixed-point precision of the on-chain risk-control system.
- Calculations must not be truncated or rounded using the display decimal places in API responses.
- Comparisons use
>=; equality with the required amount is sufficient. - Even if the difference is smaller than the API display precision, the request is rejected when the internal exact value is below the requirement.
- API fields such as
availBal,availEq,upl, andavgPxare estimates only and cannot guarantee reproduction of the final on-chain validation result. coinMaxTransferis the internal transferable amount used in risk validation.- If OpenAPI does not return
coinMaxTransferdirectly, use the synchronous receipt or the on-chain result fromGET /trade/transactionas the final determination. - Having
0.000001available balance does not by itself mean that funds are sufficient. It must be compared againstrequiredTransferTotalusing internal precision.
Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | Object | Yes | Business action object included in the EIP-712 signature. Must not contain positionSide. |
| > type | String | Yes | Fixed as updateMarginMode. |
| > assetId | String | Yes | perp instrument ID. |
| > marginMode | String | Yes | Target margin mode: cross or isolated. |
| nonce | Number | Yes | Current timestamp in milliseconds, used for signing and replay protection. |
| user | String | Yes | Master account address. |
| vaultAddress | String | No | Sub-account address. When provided, the specified sub-account is updated. |
| signature | Object | Yes | EIP-712 ECDSA signature. |
| > Ecdsa | Object | Yes | ECDSA signature object. |
| >> r | String | Yes | Signature r value prefixed with 0x. |
| >> s | String | Yes | Signature s value prefixed with 0x. |
| >> v | Number | Yes | Signature recovery value: 0 or 1. |
Margin mode is a unified assetId-level setting. In hedge mode, long and short for the same assetId must switch together and cannot use different marginMode values.
Request Example: Master Account, cross to isolated
{
"action": {
"type": "updateMarginMode",
"assetId": "102",
"marginMode": "isolated"
},
"nonce": 1708930100000,
"user": "0x742d35cc00000000000000000000000000000000",
"signature": {
"Ecdsa": {
"r": "0x1111111111111111111111111111111111111111111111111111111111111111",
"s": "0x2222222222222222222222222222222222222222222222222222222222222222",
"v": 1
}
}
}
Request Example: Sub-account, isolated to cross
{
"action": {
"type": "updateMarginMode",
"assetId": "102",
"marginMode": "cross"
},
"nonce": 1708930100001,
"user": "0x742d35cc00000000000000000000000000000000",
"vaultAddress": "0x6d1a19e1e03b83163fb38d7336b58875e71c50c2",
"signature": {
"Ecdsa": {
"r": "0x1111111111111111111111111111111111111111111111111111111111111111",
"s": "0x2222222222222222222222222222222222222222222222222222222222222222",
"v": 1
}
}
}
Response: Successful Synchronous Mode
The endpoint synchronously waits for the on-chain receipt. The response structure matches the transaction receipt returned by GET /trade/transaction.
A successful updateMarginMode receipt is Empty and omits response. Clients must not treat a missing response as an error; use status="ok" to determine that on-chain execution succeeded.
{
"code": "0",
"msg": "",
"data": [
{
"blockHash": "0xbb177081b88369e4005bbf2098632579441b3b7b9c405a52d4d54fb03df15ee7",
"blockHeight": "109575200",
"txHash": "0x518a4e71ad4525b3fa2fad9f4c9284d13e23af022c081b9d065f047976b831a0",
"txIndex": "0",
"status": "ok"
}
]
}
After synchronous success:
code="0"means OpenAPI successfully retrieved the transaction receipt.status="ok"meansupdateMarginModeexecuted successfully on-chain.- An omitted
responsemeans the successful Action receipt is Empty. - Use
GET /account/leverage-infoto confirm the latestmarginMode. - If the setting actually changed, the update can also be received through
exchangeos-setting-updates.
Response: On-Chain Failure in Synchronous Mode
If the transaction is on-chain but fails business validation, the outer code remains "0", while status is "err". The failure reason is in response.code and response.message.
The following example shows nonce validation failure:
{
"code": "0",
"msg": "",
"data": [
{
"blockHash": "0xbb177081b88369e4005bbf2098632579441b3b7b9c405a52d4d54fb03df15ee7",
"blockHeight": "109575200",
"txHash": "0x518a4e71ad4525b3fa2fad9f4c9284d13e23af022c081b9d065f047976b831a0",
"txIndex": "0",
"status": "err",
"response": {
"code": "30004",
"message": "Nonce validation failed"
}
}
]
}
In this case:
- The margin-mode switch failed.
- The original
marginModeremains unchanged. - The original positions, leverage, and funds remain unchanged.
- Do not determine success using only outer
code="0". - Do not resubmit using the same
nonce.
Response: Receipt Not Returned in Time in Synchronous Mode
When the transaction has been accepted but an on-chain receipt is not received during the synchronous wait, the endpoint returns 80106 and preserves txHash in data.
{
"code": "80106",
"msg": "transaction accepted but receipt notification was not received",
"data": [
{
"txHash": "0x518a4e71ad4525b3fa2fad9f4c9284d13e23af022c081b9d065f047976b831a0"
}
]
}
80106 is not a final failure. The transaction may have executed successfully. Do not submit it again; query the final result using the txHash:
GET /api/v5/exchangeos/trade/transaction?txHash=0x518a4e71ad4525b3fa2fad9f4c9284d13e23af022c081b9d065f047976b831a0POST /account/adjust-isolated-margin - Adjust Isolated Margin#
Adds or removes margin for an isolated position. This is a write operation; the SDK constructs an updateIsolatedMargin action.
The adjustment direction is specified by direction, not by the sign of amount. amount must always be greater than 0.
The target position must already exist. Otherwise, the isolated-margin adjustment fails.
Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | Object | Yes | Business action object included in the EIP-712 signature. |
| > type | String | Yes | Fixed as updateIsolatedMargin. |
| > assetId | String | Yes | perp instrument ID. |
| > positionSide | String | Yes | Target isolated position side: long or short. |
| > direction | String | Yes | Adjustment direction: crossToIso adds isolated margin; isoToCross removes isolated margin. |
| > amount | String | Yes | Adjustment amount. Must be greater than 0. |
| nonce | Number | Yes | Current timestamp in milliseconds, used for signing and replay protection. |
| user | String | Yes | Master account address. |
| vaultAddress | String | No | Sub-account address. When provided, the specified sub-account is updated. |
| signature | Object | Yes | EIP-712 ECDSA signature. |
Constraints
- The target position must exist and use
isolatedmargin mode. - The maximum
crossToIsoamount is the account's available margin. - The maximum
isoToCrossamount is the amount that can be released without violating maintenance margin requirements.
Request Example: Add 100 USDS of Isolated Margin
{
"action": {
"type": "updateIsolatedMargin",
"assetId": "102",
"positionSide": "long",
"direction": "crossToIso",
"amount": "100"
},
"nonce": 1708930500000,
"user": "0x9a8f...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"txHash": "0x..."
}
]
}
POST /account/set-position-mode - Set Position Mode#
Switches between oneWay and hedge. The configuration scope is the account; master accounts and sub-accounts are configured independently.
Preconditions
- The account must have no positions.
- The account must have no regular resting orders, Trigger orders, or Attached TPSL orders.
- A request whose target value equals the current
positionModeis treated as a no-op.
Leverage Inheritance Rules
oneWay to hedge
- Long leverage equals the original net leverage.
- Short leverage equals the original net leverage.
- If an
assetIdcurrently usesisolated, long and short leverage can be adjusted separately after the switch.
hedge to oneWay
- Net leverage uses the lower of long leverage and short leverage.
Switching positionMode does not change the current marginMode of any assetId.
Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| action | Object | Yes | Business action object included in the EIP-712 signature. |
| > type | String | Yes | Fixed as updatePositionMode. |
| > mode | String | Yes | Target position mode: oneWay or hedge. |
| nonce | Number | Yes | Current timestamp in milliseconds, used for signing and replay protection. |
| user | String | Yes | Master account address. |
| vaultAddress | String | No | Sub-account address. When provided, the specified sub-account is updated. |
| signature | Object | Yes | EIP-712 ECDSA signature. |
Request Example: Switch the Master Account to hedge
{
"action": {
"type": "updatePositionMode",
"mode": "hedge"
},
"nonce": 1708930550000,
"user": "0x742d35cc...",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Request Example: Switch a Sub-account to hedge
{
"action": {
"type": "updatePositionMode",
"mode": "hedge"
},
"nonce": 1708930550001,
"user": "0x742d35cc...",
"vaultAddress": "0x6d1a19e1e03b83163fb38d7336b58875e71c50c2",
"signature": {
"Ecdsa": {
"r": "0x...",
"s": "0x...",
"v": 1
}
}
}
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"txHash": "0x..."
}
]
}
GET /account/leverage-info - Leverage Information#
Retrieves the effective leverage configuration and currently permitted maximum leverage for an account and specified perp instrument.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| assetId | String | Yes | perp instrument ID. |
| positionSide | String | No | In hedge + isolated mode, specify long or short. |
| vaultAddress | String | No | Sub-account address. Omit to query the master account. |
Request Example: All Effective Leverage Settings
GET /api/v5/exchangeos/account/leverage-info?assetId=102Request Example: long in hedge + isolated Mode
GET /api/v5/exchangeos/account/leverage-info?assetId=102&positionSide=longRequest Example: Sub-account Query
GET /api/v5/exchangeos/account/leverage-info?assetId=102&vaultAddress=0x6d1a19e1e03b83163fb38d7336b58875e71c50c2Return Rules
- In hedge + cross mode,
maxLeveragemust be calculated separately for long and short positions and opening orders. The endpoint returns the lower value because a shared leverage update affects both sides. - In hedge + isolated mode,
maxLeverageis calculated independently for long and short.
Response Fields
| Field | Type | Description |
|---|---|---|
| assetId | String | Instrument ID. |
| marginMode | String | Margin mode: cross or isolated. |
| positionSide | String | Position side. Returns long or short in hedge + isolated mode. |
| leverage | String | Current effective leverage. |
| maxLeverage | String | Maximum leverage currently permitted. |
Response Example: oneWay + cross
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"marginMode": "cross",
"leverage": "10",
"maxLeverage": "30"
}
]
}
Response Example: oneWay + isolated
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"marginMode": "isolated",
"leverage": "10",
"maxLeverage": "25"
}
]
}
These are examples of two independent states. The same account and assetId do not return both cross and isolated simultaneously.
Response Example: hedge + cross
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"marginMode": "cross",
"leverage": "8",
"maxLeverage": "20"
}
]
}
Response Example: hedge + isolated
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"marginMode": "isolated",
"positionSide": "long",
"leverage": "10",
"maxLeverage": "30"
},
{
"assetId": "102",
"marginMode": "isolated",
"positionSide": "short",
"leverage": "5",
"maxLeverage": "20"
}
]
}
GET /account/trade-fee - Trade Fee Rates#
Retrieves trading fee rates for a specified instrument.
Fee sign rules:
- A positive value means the platform charges a fee.
- A negative value means a rebate. Actual rates may vary by account level or fee program.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| assetId | String | No | Instrument ID. |
Request Example
GET /api/v5/exchangeos/account/trade-fee?assetId=102Response Fields
| Field | Type | Description |
|---|---|---|
| assetId | String | Instrument ID. |
| taker | String | Taker fee rate. A positive value is a fee; a negative value is a rebate. |
| maker | String | Maker fee rate. A positive value is a fee; a negative value is a rebate. |
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"assetId": "102",
"taker": "0.000500",
"maker": "0.000200"
}
]
}
GET /account/bills - Bills#
Retrieves account balance-change records. Each record corresponds to one balance change and is traceable, reconcilable, and idempotent. The endpoint covers perp and spot, follows semantics aligned with order history, and returns at most one year of data.
balChg is a String:
- A positive value indicates a balance increase or credit.
- A negative value indicates a balance decrease or debit.
- For example, a fee debit may be
balChg="-0.00196", whilefills.fee="0.00196"represents the fee amount. The two fields have different meanings.
Pagination Rules
- Records are located in
data[0].dataand are returned in descending order bycTime. - Each response returns the next-page token in
data[0].nextCursor. The token is opaque; clients must not parse or construct it. - Use
data[0].hasMoreto determine whether to request another page.hasMore=falsewithnextCursor=""indicates the final page. - Do not determine the end of pagination from a returned record count smaller than
limit. When filters such asbillTypeorflowCategoryare used, a page can contain fewer records thanlimitwhile additional data still exists. beginandendare time-window filters only; they are not pagination cursors. When passed withcursor,cursordetermines the starting position.- Do not pass
cursoron the first page. billIdis a global monotonic sequence shared across the entire market. It is not guaranteed to be continuous in a single user's view. Do not infer record counts from numeric gaps or treat gaps as lost data. The pagination contract guarantees completeness.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| billType | String | No | Filters by bill type. |
| flowCategory | String | No | Filters by fund-flow category. |
| assetId | String | No | Filters by instrument ID. |
| begin | String | No | Start of the query time window, as a Unix timestamp in milliseconds. |
| end | String | No | End of the query time window, as a Unix timestamp in milliseconds. |
| cursor | String | No | Pagination token returned by the previous page. Omit for the first page. |
| limit | String | No | Number of records to return. |
| vaultAddress | String | No | Sub-account address. Omit to query the master account. |
Request Examples
GET /api/v5/exchangeos/account/bills?billType=funding_fee&assetId=102&limit=100
GET /api/v5/exchangeos/account/bills?cursor=1&limit=100
GET /api/v5/exchangeos/account/bills?flowCategory=transfer&begin=1704067200000&end=1704070800000&limit=100Response Fields
| Field | Type | Description |
|---|---|---|
| data | Array | Bill records. |
| > assetId | String | Instrument ID. Returns an empty string when not applicable. |
| > bal | String | Balance after the change. |
| > balChg | String | Balance change amount. A positive value is a credit; a negative value is a debit. |
| > billId | String | Bill ID. A global monotonic market-wide sequence; not guaranteed to be continuous for one user. |
| > billType | String | Bill type. |
| > cTime | String | Bill creation time, as a Unix timestamp in milliseconds. |
| > flowCategory | String | Fund-flow category. |
| > from | String | Source address. Returns an empty string when not applicable. |
| > marginMode | String | Margin mode. Returns an empty string when not applicable. |
| > oid | String | Related order ID. Returns an empty string when not applicable. |
| > to | String | Destination address. Returns an empty string when not applicable. |
| > tokenId | String | Token ID. |
| > tradeId | String | Related trade ID. Returns an empty string when not applicable. |
| hasMore | Boolean | Whether additional records are available. |
| nextCursor | String | Token for retrieving the next page. Returns an empty string on the final page. |
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"data": [
{
"assetId": "",
"bal": "100",
"balChg": "+100",
"billId": "137074380-27-0",
"billType": "deposit",
"cTime": "1790068571545",
"flowCategory": "transfer",
"from": "",
"marginMode": "",
"oid": "",
"to": "0x112001ee52b6a119272b273f9062208f7d75c6fd",
"tokenId": "1771",
"tradeId": ""
}
],
"hasMore": false,
"nextCursor": ""
}
]
}
GET /account/detail - Account Details#
Retrieves account Agents, sub-accounts, master-account relationships, user level, and other account-level settings.
Request Parameters
None.
Request Example
GET /api/v5/exchangeos/account/detailResponse Fields
| Field | Type | Description |
|---|---|---|
| user | String | Current account address. |
| parentAccount | String | Master account address. The master account returns an empty string. |
| subAccounts | Array | Sub-account list. |
| > address | String | Sub-account address. |
| > positionMode | String | Sub-account position mode: oneWay or hedge. |
| positionMode | String | Current account position mode: oneWay or hedge. |
| level | String | User level. |
| ip | String | Configured IP address list. |
| agents | Array | Agent list. |
| > address | String | Agent address. |
| > status | String | Agent status, such as active or expired. |
| > expiry | String | Agent expiry time, as a Unix timestamp in milliseconds. |
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
"parentAccount": "",
"subAccounts": [
{
"address": "0x6d1a19e1e03b83163fb38d7336b58875e71c50c2",
"positionMode": "hedge"
},
{
"address": "0x93f51fc5190b1e7bb82238bcc2f93430b43a9243",
"positionMode": "oneWay"
}
],
"positionMode": "oneWay",
"level": "VIP5",
"ip": "117.37.203.58,117.37.203.57",
"agents": [
{
"address": "0xa880d6cc607a05ea617307ab3b0d335e8d8424ee",
"status": "active",
"expiry": "1816754400000"
},
{
"address": "0x1563915e194d8cfba1943570603f7606a3115508",
"status": "expired",
"expiry": "1785218400000"
}
]
}
]
}
GET /account/limits - Account Limits#
Retrieves the effective on-chain trading limits for the master account or a specified sub-account, including Action allowance, daily cancelAll limit, cancellation exemption allowance, and open-order limits.
Master-account and sub-account limits are recorded and calculated separately by account address. They do not share allowances or usage. For batch transactions, allowance usage is based on the number of transactions in the batch.
Action Limit and actionLimit.used Rules
Each wallet address has an Action allowance for on-chain trading operations:
- Every wallet address starts with 30,000 Actions.
- By default, every 1 USD of completed trading volume earns 1 additional Action limit.
- Regular order placement, cancellation, and modification each consume 1 Action used.
cancelAllconsumes 5 Actions used. - The cancellation limit is
min(actionLimit × 2, limit + 200,000). - When
action_used >= limit, regular Actions enter throttling. Whenaction_used >= cancel_limit, cancellation requests enter throttling. - In throttled status, one request may be submitted every 5 seconds.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| vaultAddress | String | No | Sub-account address. Omit to query the master account; provide it to query the specified sub-account. The gateway verifies that the address belongs to the authenticated user. Master and sub-account limits are recorded and calculated independently. |
Request Examples
GET /api/v5/exchangeos/account/limits
GET /api/v5/exchangeos/account/limits?vaultAddress=0x6d1a19e1e03b83163fb38d7336b58875e71c50c2Response Fields
| Field | Type | Description |
|---|---|---|
| actionLimit | Object | User Action request allowance. |
| > initial | String | Initial Action allowance. |
| > earned | String | Action allowance earned from trading volume. |
| > purchased | String | Action allowance purchased through reserveRequestWeight. |
| > granted | String | Additional Action allowance granted through governance settings. |
| > used | String | Cumulative Action allowance consumed since the account began recording. It does not reset daily. Batch operations accumulate based on internal Action count. |
| > remaining | String | Currently available Action allowance, based on the server-calculated result. |
| > isThrottled | Boolean | Whether the account is throttled. |
| > throttleIntervalMs | String | Minimum request interval after throttling, in milliseconds. The current configured value is still returned when not throttled. |
| cancelAll | Object | User daily cancelAll limit. |
| > dailyLimit | String | Total allowed cancelAll calls in the current accounting period. |
| > used | String | cancelAll calls used in the current period. Resets daily. |
| > remaining | String | Remaining cancelAll calls available in the current accounting period. |
| > periodStartMs | String | Start time of the current accounting period, as a Unix timestamp in milliseconds. |
| > periodEndMs | String | End time of the current accounting period, as a Unix timestamp in milliseconds. |
| cancelExemption | Object | Dedicated exemption allowance for cancelling existing resting orders after the Action allowance is limited. |
| > limit | String | Cumulative exemption allowance available for cancellation operations. |
| > remaining | String | Remaining cancellation exemption allowance. |
| openOrders | Object | Current open-order count and open-order limit. |
| > current | String | Current number of uncompleted orders. |
| > limit | String | Currently effective open-order limit. |
| > userOverride | String | Open-order limit set specifically by an administrator. Returns "" when not configured and "0" when explicitly configured as zero. |
| block_timestamp | String | On-chain block time corresponding to the query result, as a Unix timestamp in milliseconds. |
| block_height | String | On-chain block height corresponding to the query result. |
When openOrders.userOverride is configured, openOrders.limit uses that value directly. Otherwise:
openOrders.limit
= min(
initial_limit + weighted_volume / volume_per_extra_order,
max_limit
)
weighted_volume
= spot trading volume
+ perp trading volume
+ prediction trading volume × prediction_volume_multiplierDefault values:
initial_limit = 2000
volume_per_extra_order = 1,000,000
max_limit = 10000
prediction_volume_multiplier = 10Clients should use openOrders.limit as the actual effective open-order limit.
Response Example
{
"code": "0",
"msg": "",
"data": [
{
"actionLimit": {
"initial": "30000",
"earned": "125000",
"granted": "0",
"purchased": "10000",
"used": "20000",
"remaining": "145000",
"isThrottled": false,
"throttleIntervalMs": "5000"
},
"cancelAll": {
"dailyLimit": "10",
"periodStartMs": "1789056000000",
"periodEndMs": "1789142400000",
"remaining": "8",
"used": "2"
},
"cancelExemption": {
"limit": "330000",
"remaining": "320000"
},
"openOrders": {
"current": "128",
"limit": "2000",
"userOverride": "0"
},
"block_timestamp": "1789092000074",
"block_height": "12092410"
}
]
}
- GET /account/balance - Account BalanceGET /account/positions - PositionsGET /account/max-size - Maximum Order SizeGET /account/position-tiers - Effective User Position TiersPOST /account/set-leverage - Set LeveragePOST /account/set-margin-mode - Set Margin ModePOST /account/adjust-isolated-margin - Adjust Isolated MarginPOST /account/set-position-mode - Set Position ModeGET /account/leverage-info - Leverage InformationGET /account/trade-fee - Trade Fee RatesGET /account/bills - BillsGET /account/detail - Account DetailsGET /account/limits - Account Limits
