Entwicklerportal
Anzeigemodus

Private WebSocke#

Private WebSocket Subscription Guidelines#

All private channels are subscribed to through the WebSocket subscribe operation. Unless stated otherwise, id is client-defined; use vaultAddress for a sub-account, pointBoard defaults to false, and marketTypes defaults to all markets.

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "<channel>",
      "vaultAddress": "xxxxx",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Backend Connection Prewarming (connect_backends)#

ExchangeOS private channels support establishing Backend connections before subscription to reduce latency for the first subscription and the first data push. The Backend for ExchangeOS private channels is okx-defi-tradezone-indexerpubsub-awstky-pro. connect_backends only prewarms the connection; it does not create a channel subscription or replace subscribe.

After login succeeds and before sending subscribe, clients may send:

json
{
  "id": "req-connect-1",
  "op": "connect_backends",
  "args": [
    {
      "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro"
    }
  ]
}

A successful connect_backends request does not return a synchronous request-level success response. The Backend connection is established only after the following asynchronous event is received:

json
{
  "event": "backend",
  "code": 0,
  "msg": "Success",
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "extraInfo": "",
  "connId": "50b71049"
}

Recommended sequence: establish the WebSocket connection → complete private-channel login → send connect_backends → wait for event=backend with code=0 → send subscribe → receive event=subscribe → receive channel data.

connect_backends is an optional connection-prewarming mechanism. If the client does not send it, the first subscribe still triggers lazy connection establishment and the existing subscription flow continues to work. The event order is event=backend with code=0 → event=subscribe → channel data.

Backend Connection Status Event (event: backend)#

event=backend is a server-initiated event that reports the connection status of a Backend. It is neither a response to a specific request nor channel data.

This event informs clients that the connection between the push service and a Backend has been interrupted, or that the connection and subscriptions have been restored. The push service automatically reconnects and restores subscriptions; clients do not need to resend connect_backends or subscribe.

Trigger Conditions#

StatusTrigger Scenariocodemsg
Backend connection established for the first timeTriggered by connect_backends, or by lazy connection establishment initiated through send/subscribe, and the Backend connection is successfully established.0Success
Backend connection disconnected unexpectedlyThe push service receives a gRPC onError. The WebSocket remains active, while the push service starts automatic reconnection and subscription recovery.50011Backend stream disconnected
Backend connection closed by the serverThe push service receives a gRPC onCompleted. The WebSocket remains active, while the push service starts automatic reconnection and subscription recovery.50012Backend stream completed by server
Backend connection and subscriptions restoredThe push service completes reconnection and automatically restores active subscriptions for that Backend.0Success

Frame Format#

json
{
  "event": "backend",
  "code": 0,
  "msg": "Success",
  "backend": "core-trading-v2",
  "extraInfo": "",
  "connId": "abcd1234"
}
FieldDescription
eventAlways backend.
code0: connection established; 50011: abnormal disconnection; 50012: server-side closure.
msgStatus description.
backendIdentifier of the Backend whose status changed.
extraInfoReserved field; currently always an empty string.
connIdCurrent WebSocket connection ID.

Client Handling Guidelines#

  • event=backend does not mean that the WebSocket connection has closed. The WebSocket remains active; only the connection between the push service and a Backend has changed.
  • After receiving code=50011 or code=50012, clients do not need to resend connect_backends or subscribe, and do not need to close or recreate the WebSocket connection. The push service automatically reconnects to the Backend and restores subscriptions.
  • Clients without data-reconciliation requirements may simply recognize, log, or ignore event=backend; no additional handling is required.
  • Automatic recovery only ensures that messages continue after recovery. It cannot replay business messages missed while the Backend connection was unavailable.
  • Clients that require data completeness for orders, fills, positions, assets, or similar data may record the timestamps of code=50011/50012 and the subsequent code=0. After receiving the recovery event, they may query the latest state through the relevant REST APIs, reconcile data, or perform business-level recovery.
  • If the WebSocket connection itself is closed, follow the existing WebSocket reconnection, login, and resubscription flow. A WebSocket disconnection and a Backend downstream connection interruption represented by event=backend are different conditions.

exchangeos-balance-and-position - Scheduled Account and Position Snapshots#

Pushes a complete account and position snapshot every 5 seconds. Periodic snapshots do not include Position tradeId.

The request id can be user-defined.

Subscribe#

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-balance-and-position",
      "vaultAddress": "xxxxx",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}
ParameterTypeRequiredDescription
idStringYesA user-defined request ID.
opStringYesFixed value: subscribe.
argsArrayYesSubscription argument list.
> channelStringYesFixed value: exchangeos-balance-and-position.
> vaultAddressStringNoSub-account address. Omit this field to subscribe to the master account.
> pointBoardStringNotrue for the points board and false for the live board. Default: false.
> marketTypesStringNoMarket type filter, for example ["spot", "perp"]. Defaults to all supported market types.

Snapshot Pagination Rules#

  • type, curPage, lastPage, totalCount, and activeCount are located inside data.
  • data is an object. Do not expect the format data: [{ "orders": [] }].
  • All pages in the same snapshot cycle have the same block_height, block_timestamp, totalCount, and activeCount.
  • pTime represents the actual generation time of each page and can differ across pages.
  • Clients should collect all pages and apply the snapshot atomically after receiving lastPage=true.
  • When there are no applicable records, the channel still returns empty arrays and corresponding zero counts.

Top-Level Push Fields#

FieldTypeDescription
argObjectSubscription information.
> channelStringFixed value: exchangeos-balance-and-position.
> vaultAddressStringSub-account address. Omitted when subscribing to the master account.
> marketTypesStringMarket type filter used for the subscription.
> pointBoardStringBoard type used for the subscription.
backendStringBackend identifier that serves the subscription.
block_heightStringOn-chain block height for this snapshot.
block_timestampStringOn-chain block timestamp for this snapshot, in Unix milliseconds.
pTimeStringActual WebSocket message generation time, in Unix milliseconds.
userStringMaster-account or sub-account address associated with this snapshot.
dataObjectComplete account and position snapshot.

data Fields#

FieldTypeDescription
typeStringFixed value: snapshot.
curPageStringCurrent snapshot page number.
lastPageBooleanWhether this is the final page of the current snapshot cycle.
assetsCntStringTotal number of token records in the complete snapshot.
positionsCntStringTotal number of position records in the complete snapshot.
totalEqStringTotal account equity. Includes all business lines; perp includes cross and isolated equity.
notionalUsdStringTotal account-level position notional value in USD.
positionModeStringPosition mode: oneWay or hedge.
detailsArrayToken balance details. Tokens with both cashBal and eq equal to 0 are omitted, except USDS.
positionsArrayperpetual position details.

details[] Fields#

FieldTypeDescription
tokenIdStringToken ID.
collateralEnabledBooleanWhether the token can be used as collateral.
cashBalStringToken balance, including funds frozen by perp and spot orders.
availBalStringAvailable token balance. Only collateral tokens have a value.
frozenMgnStringTotal frozen amount. For collateral tokens, includes spot, perp, and Prediction Market frozen amounts. For non-collateral tokens, includes only spot and Prediction Market frozen amounts.
frozenMgnRatioStringFrozen margin ratio.
perpFrozenStringMargin frozen by perp positions and open orders.
spotFrozenStringAmount frozen by spot open orders.
predFrozenStringAmount frozen by Prediction Market activity.
lastPxStringLatest trade price. Returns an empty string when unavailable.
tokenPxStringToken USD price. spot USD valuation uses tokenPx first, then lastPx if unavailable.
marketTypeStringMarket type.
accAvgPxStringAverage acquisition cost.
spotUplStringspot unrealized profit and loss.
entryCostStringTotal spot holding cost.
spotUplRatioStringspot unrealized profit and loss ratio.
availEqStringAvailable margin.
uplStringCross-margin unrealized profit and loss.
eqStringTotal cross-margin and isolated-margin equity.
eqUsdStringUSD value of eq, calculated using eq * tokenPx.
isoUplStringIsolated-margin unrealized profit and loss.
isoEqStringTotal isolated-margin equity.
totalLeverStringPosition leverage calculated as coinPosValue / coinEquity. Returns an empty string when unavailable.
mmrStringMaintenance margin. It is the sum of position maintenance margins and liquidation fees, excluding isolated margin.
mgnRatioStringMaintenance margin ratio. Returns an empty string when unavailable.

positions[] Fields#

FieldTypeDescription
assetIdStringAsset ID.
positionSideStringPosition side: net, long, or short. net is used in one-way mode; long and short are used in hedge mode.
marginModeStringMargin mode: cross or isolated.
posStringPosition size.
leverageStringLeverage. Only integer leverage is supported. Returns an empty string when equity is 0.
avgPxStringAverage position price.
fundingFeeStringCumulative funding fee since the position was opened.
imrStringInitial margin. For cross margin, calculated as notional value divided by leverage. Returns an empty string when the mark price is unavailable.
mmrStringMaintenance margin.
mgnRatioStringMaintenance margin ratio. For cross margin, it uses the token-level maintenance margin ratio; for isolated margin, it is calculated from the position.
markPxStringMark price.
lastPxStringLatest trade price.
idxPxStringLatest index price for the underlying. Returns an empty string when unavailable.
positionValueStringPosition value in USD.
quoteUsdPxStringUSD price of the quote token.
liqPxStringEstimated liquidation price.
uplStringUnrealized profit and loss calculated using the mark price.
uplRatioStringUnrealized profit and loss ratio calculated using the mark price.
uplLastPxStringUnrealized profit and loss calculated using the latest trade price.
uplRatioLastPxStringUnrealized profit and loss ratio calculated using the latest trade price.
marginStringIsolated margin balance. Returns an empty string for cross-margin positions.
pnlStringClosed-position profit and loss.
realizedPnlStringRealized profit and loss.
feeStringCumulative trading fee for the position.
closeOrderAlgoArrayPosition TP/SL orders.
tpLimitOrdersArrayPosition TP Limit orders.
assetStatusStringContract status: normal, scheduled, converging, or regressing.

closeOrderAlgo[] Fields#

FieldTypeDescription
oidStringOn-chain order ID.
assetIdStringAssociated perp asset ID.
assetStatusStringContract status.
cTimeStringOrder creation time, in Unix milliseconds.
sideStringClosing-order side: buy or sell.
positionSideStringAssociated position side: net, long, or short.
marginModeStringAssociated margin mode: cross or isolated.
leverageStringPosition leverage.
sizeStringClosing size, measured in base currency units.
reduceOnlyBooleanWhether the order is reduce-only.
triggerPxStringTrigger price.
triggerPriceTypeStringTrigger price type: mark or index.
triggerCondStringTrigger condition: gte or lte.
isMarketBooleanWhether the order is executed at market after it is triggered.
tpslStringTPSL type: tp or sl.
tpLimitBooleanWhether this is a TP Limit order.
isActiveBooleanWhether the TP/SL order is active.

tpLimitOrders[] Fields#

FieldTypeDescription
oidStringOn-chain order ID.
assetIdStringAssociated perp asset ID.
assetStatusStringContract status.
cTimeStringOrder creation time, in Unix milliseconds.
sideStringClosing-order side: buy or sell.
positionSideStringAssociated position side.
marginModeStringAssociated margin mode.
leverageStringPosition leverage.
priceStringTP Limit order price.
sizeStringOrder size, measured in base currency units.
accFillSzStringCumulative filled size.
reduceOnlyBooleanWhether the order is reduce-only.
tpslStringFixed value: tp.
tpLimitBooleanFixed value: true.

Response Example#

json
{
  "arg": {
    "channel": "exchangeos-balance-and-position",
    "marketTypes": "[\"all\"]",
    "pointBoard": "false"
  },
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "block_height": "42775890",
  "block_timestamp": "1788157193630",
  "data": {
    "assetsCnt": "2",
    "curPage": "0",
    "details": [
      {
        "accAvgPx": "",
        "availBal": "200.015022",
        "availEq": "3351.725522",
        "cashBal": "200.015022",
        "collateralEnabled": true,
        "entryCost": "",
        "eq": "3739.515022",
        "eqUsd": "3739.515022",
        "frozenMgn": "387.789500",
        "frozenMgnRatio": "0.1037",
        "isoEq": "0.000000",
        "isoUpl": "0.000000",
        "marketType": "spot",
        "mgnRatio": "0.005703",
        "mmr": "19.389475",
        "perpFrozen": "387.789500",
        "predFrozen": "0.000000",
        "spotFrozen": "0.000000",
        "spotUpl": "",
        "spotUplRatio": "",
        "tokenId": "0",
        "tokenPx": "1",
        "totalLever": "1.037004",
        "upl": "3539.500000"
      }
    ],
    "lastPage": true,
    "notionalUsd": "3877.895",
    "positionMode": "hedge",
    "positions": [
      {
        "assetId": "602",
        "assetStatus": "normal",
        "avgPx": "3000.000",
        "closeOrderAlgo": [
          {
            "assetId": "602",
            "assetStatus": "normal",
            "cTime": "1788156156130",
            "isActive": true,
            "isMarket": true,
            "leverage": "10",
            "marginMode": "cross",
            "oid": "117984458",
            "positionSide": "long",
            "reduceOnly": true,
            "side": "sell",
            "size": "0.100",
            "tpLimit": false,
            "tpsl": "tp",
            "triggerCond": "gte",
            "triggerPriceType": "mark",
            "triggerPx": "80000.000"
          }
        ],
        "fee": "-3.750000",
        "fundingFee": "23562.904548",
        "idxPx": "38390.000",
        "imr": "383.950000",
        "lastPx": "38395.000",
        "leverage": "10",
        "liqPx": "625.632",
        "marginMode": "cross",
        "markPx": "38395.000",
        "mgnRatio": "0.005703",
        "mmr": "19.197500",
        "pnl": "0.000000",
        "pos": "0.100",
        "positionSide": "long",
        "positionValue": "3839.5",
        "quoteUsdPx": "1",
        "realizedPnl": "23559.154548",
        "tpLimitOrders": [],
        "upl": "3539.500000",
        "uplLastPx": "3539.500000",
        "uplRatio": "9.218648",
        "uplRatioLastPx": "9.218648"
      }
    ],
    "positionsCnt": "2",
    "totalEq": "3756.498022",
    "type": "snapshot"
  },
  "pTime": "1788157193711",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb"
}

Account and Position Event Updates exchangeos-balance-and-position-updates#

A private account and position update channel for Open API developers.

After a successful subscription, the channel pushes incremental data by event whenever balance, Position, or account data changes.

When a Position is fully closed, the incremental update still returns that Position with pos set to "0".

The subscription request id can be user-defined.

Subscribe to the Master Account#

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-balance-and-position-updates",
      "vaultAddress": "xxxxx",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Subscribe to a Sub-account#

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-balance-and-position-updates",
      "marketTypes": "[\"spot\", \"perp\"]",
      "vaultAddress": "xxxxx"
    }
  ]
}

Subscription Parameters#

ParameterTypeRequiredDescription
idStringYesUser-defined request ID.
opStringYesFixed value: subscribe.
argsArrayYesSubscription argument list.
> channelStringYesFixed value: exchangeos-balance-and-position-updates.
> vaultAddressStringNoSub-account address. Omit when subscribing to the master account.
> pointBoardStringNotrue for the points board and false for the live board. Default: false.
> marketTypesStringNoMarket types, for example ["spot", "perp"]. All market types are returned by default.

Top-Level Push Fields#

FieldTypeDescription
argObjectSubscription information.
> channelStringFixed value: exchangeos-balance-and-position-updates.
> vaultAddressStringSub-account address. Omitted when subscribing to the master account.
block_heightStringOn-chain block height associated with this update.
block_timestampStringOn-chain block time associated with this update, in Unix milliseconds. It has the same semantics as uTime and is the data version for data.details[] and data.positions[].
pTimeStringActual WebSocket message generation or push time, in Unix milliseconds. Not used for data deduplication.
userStringMaster-account or sub-account address associated with this update.
dataObjectThe first message is a complete account snapshot. Subsequent messages contain account, Token, and Position updates involved in the event. type is located inside data.

data Fields#

FieldTypeDescription
typeStringData mode: snapshot or update.
eventTypeStringBusiness event type that caused this data update.
totalEqStringTotal live-account equity in USD after the event is processed. Excludes points-board assets.
notionalUsdStringSum of the absolute USD notional values of all perp positions after the event is processed. Includes cross and isolated positions. Hedge-mode long and short positions are not netted. Excludes open orders.
positionModeStringAccount position mode: oneWay or hedge.
detailsArrayLatest state of Tokens involved in this event.
positionsArrayLatest state of perp Positions involved in this event.
tradesArrayTrade identifier list involved in this event. Returns [] for the initial snapshot or when there are no ordinary matching trades.

type and eventType have different meanings:

  • data.type indicates the data mode: snapshot or update.
  • data.eventType indicates the business event that caused this incremental update.
  • When type="snapshot", eventType returns "". Do not use eventType to determine whether data is a full snapshot or an incremental update.

details[] Fields#

FieldTypeDescription
tokenIdStringToken ID. USDS is "0".
marketTypeStringMarket type.
collateralEnabledBooleanWhether the Token can be used as collateral. USDS and independent points-board Tokens can be true; standard spot Tokens are false.
eqStringTotal Token equity in native Token units. For collateral Tokens, this is the sum of cross-margin and isolated-margin equity.
eqUsdStringTotal Token equity valuation. Live-board Tokens are converted to USD; points-board Tokens use the display convention of 1 Point = 1 USD.
isoEqStringIsolated-margin equity in native collateral Token units. Returns "" for non-collateral Tokens.
cashBalStringToken balance in native Token units, including frozen amounts.
availBalStringAvailable Token balance in native Token units.
availEqStringAvailable cross-margin collateral. Returns "" for non-collateral Tokens.
frozenMgnStringTotal Token amount in use, equal to spotFrozen + perpFrozen + predFrozen.
spotFrozenStringAmount reserved by spot open orders, in native Token units.
perpFrozenStringAmount used by perp cross-margin positions and open orders. Includes isolated-margin open-order usage but excludes isolated-position margin. Returns "" for non-collateral Tokens.
predFrozenStringAmount used by Prediction Market activity, in native Token units.
mmrStringCross-margin maintenance margin. Excludes isolated margin. Returns "" for non-collateral Tokens.
mgnRatioStringCross-margin maintenance margin ratio. Returns "" for non-collateral Tokens.
frozenMgnRatioStringCross-margin funds utilization ratio. Returns "" for non-collateral Tokens.
accAvgPxStringspot cumulative average cost price. The Phase 1 real-time channel always returns "".
spotUplStringspot unrealized profit and loss. The Phase 1 real-time channel always returns "".
spotUplRatioStringspot unrealized profit and loss ratio. The Phase 1 real-time channel always returns "".
entryCostStringTotal spot cost. The Phase 1 real-time channel always returns "".
uplStringperp cross-margin unrealized profit and loss. Returns "" for non-collateral Tokens.
isoUplStringperp isolated-margin unrealized profit and loss. Returns "" for non-collateral Tokens.
lastPxStringLatest spot trade price for this Token. Returns "" when no trade price is available.
tokenPxStringUSD valuation price of this Token. Returns "" when no valuation price is available.
totalLeverStringTotal cross-margin leverage for this collateral Token. Returns "" for non-collateral Tokens, when not applicable, or when unavailable.

positions[] Fields#

FieldTypeDescription
assetIdStringPerp product ID.
assetStatusStringContract status: normal, scheduled, converging, or regressing.
positionSideStringPosition side: net, long, or short.
marginModeStringMargin mode: cross or isolated.
leverageStringPosition leverage.
posStringPosition size in base units. A fully closed Position in an incremental event returns "0".
avgPxStringAverage entry price.
markPxStringMark price.
positionValueStringPosition notional value in USD.
uplStringUnrealized profit and loss.
uplRatioStringUnrealized profit and loss ratio.
liqPxStringEstimated liquidation price. Returns "" when unavailable.
imrStringCross-margin initial margin. Returns "" for isolated margin.
marginStringIsolated-margin balance. Returns "" for cross margin.
mmrStringMaintenance margin.
mgnRatioStringMaintenance margin ratio.
realizedPnlStringRealized profit and loss.
feeStringCumulative trading fees.
fundingFeeStringCumulative funding fees since the position was opened.
lastPxStringLatest trade price. Used for display only and not as a risk-control or deduplication reference.
idxPxStringLatest index price for the underlying. Returns "" when no index price is available.
quoteUsdPxStringUSD price of the quote Token.
pnlStringClosed-position profit and loss.
uplLastPxStringUnrealized profit and loss calculated using the latest trade price.
uplRatioLastPxStringUnrealized profit and loss ratio calculated using the latest trade price.
closeOrderAlgoArrayPosition TPSL orders associated with this Position. Returns [] when there are no associated orders.

closeOrderAlgo[] Fields#

FieldTypeDescription
oidStringOn-chain order ID of the Position TPSL.
assetIdStringperp product ID of the associated Position.
assetStatusStringProduct status: normal, scheduled, converging, or regressing.
sideStringClosing-order side: buy or sell.
positionSideStringAssociated position side: net, long, or short.
marginModeStringMargin mode of the associated Position: cross or isolated.
priceStringOrder price after triggering. Trigger Market returns "0".
sizeStringClosing size after triggering, in base units. Entire Position TPSL can return "0" and is executed using the actual position size at the time of the on-chain trigger.
reduceOnlyBooleanWhether the order is reduce-only. Position TPSL is always true.
triggerPxStringTrigger price.
triggerPriceTypeStringTrigger price type: mark or index.
triggerCondStringGte or Lte, indicating the comparison condition between the trigger reference price and triggerPx.
isMarketBooleanWhether the order is executed at market after triggering.
tpslStringPosition TPSL type: tp or sl.
parentOrderIdStringPosition TPSL has no parent order and always returns "".
isActiveBooleanWhether the Position TPSL is active.
tpLimitBooleanWhether this is a TP Limit order.

trades[] Fields#

FieldTypeDescription
assetIdStringProduct ID for the trade. Can be a perp or spot product.
tradeIdStringGlobal ordinary matching trade ID, used for trade deduplication and association with account-state updates. Non-ordinary matching events do not generate a special value.

eventType Enumeration#

ValueDescription
filledOrdinary trade fill.
liquidationLiquidation.
adlAuto-deleveraging.
settlementSettlement.
ctfOperationCTF operation.
fundingFeeFunding fee.
setLeverageLeverage update.
transferredFunds transfer.
depositDeposit.
withdrawWithdrawal.
adjustMarginMargin adjustment.
clawBackClawback.
vaultOperationVault operation.
tokenBurnToken burn.
purchaseFeePurchase fee.
orderUpdatedOrder update.

Ordinary Fill Event Example#

Two perp fills and one spot fill occur at the same on-chain timestamp:

json
{
  "arg": {
    "channel": "exchangeos-balance-and-position-updates",
    "marketTypes": "[\"all\"]",
    "pointBoard": "false"
  },
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "block_height": "42779616",
  "block_timestamp": "1788157566230",
  "pTime": "1788157566312",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "type": "update",
    "eventType": "filled",
    "totalEq": "44476.681072",
    "notionalUsd": "5071.600000",
    "positionMode": "hedge",
    "details": [
      {
        "tokenId": "0",
        "collateralEnabled": true,
        "eq": "3739.131072",
        "eqUsd": "3739.131072",
        "isoEq": "0.000000",
        "cashBal": "807.531072",
        "availBal": "807.531072",
        "availEq": "3331.971072",
        "frozenMgn": "407.160000",
        "spotFrozen": "0.000000",
        "perpFrozen": "407.160000",
        "predFrozen": "0.000000",
        "mmr": "25.358000",
        "mgnRatio": "0.006782",
        "frozenMgnRatio": "0.108892",
        "accAvgPx": "",
        "spotUpl": "",
        "spotUplRatio": "",
        "entryCost": "",
        "upl": "2931.600000",
        "isoUpl": "0.000000",
        "lastPx": "",
        "tokenPx": "1",
        "totalLever": "1.356358"
      }
    ],
    "positions": [
      {
        "assetId": "602",
        "assetStatus": "normal",
        "positionSide": "long",
        "marginMode": "cross",
        "leverage": "10",
        "pos": "0.080",
        "avgPx": "3000.000",
        "markPx": "38395.000",
        "positionValue": "3071.600000",
        "upl": "2831.600000",
        "uplRatio": "9.218648",
        "liqPx": "625.632",
        "imr": "307.160000",
        "margin": "",
        "mmr": "15.358000",
        "mgnRatio": "0.006782",
        "realizedPnl": "24266.670598",
        "fee": "-4.133950",
        "fundingFee": "23562.904548",
        "lastPx": "38395.000",
        "idxPx": "38390.000",
        "quoteUsdPx": "1",
        "pnl": "707.900000",
        "uplLastPx": "2831.600000",
        "uplRatioLastPx": "9.218648",
        "closeOrderAlgo": [],
        "tpLimitOrders": []
      }
    ],
    "trades": [
      {
        "assetId": "602",
        "tradeId": "839"
      },
      {
        "assetId": "702",
        "tradeId": "840"
      },
      {
        "assetId": "301",
        "tradeId": "841"
      }
    ]
  }
}

Partial Liquidation Event Example#

Non-ordinary matching events, such as liquidation, ADL, funding fees, and settlement, do not generate new ordinary tradeId values. Therefore, trades=[]. Use eventType to identify the event cause.

json
{
  "arg": {
    "channel": "exchangeos-balance-and-position-updates"
  },
  "block_height": "12092501",
  "block_timestamp": "1785218460000",
  "pTime": "1785218460040",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "type": "update",
    "eventType": "liquidation",
    "totalEq": "124950.960900",
    "notionalUsd": "2100.000000",
    "positionMode": "oneWay",
    "details": [
      {
        "tokenId": "0",
        "collateralEnabled": true,
        "eq": "124950.960900",
        "eqUsd": "124950.960900",
        "isoEq": "0.000000",
        "cashBal": "125100.960900",
        "availBal": "124688.460900",
        "availEq": "124688.460900",
        "frozenMgn": "262.500000",
        "spotFrozen": "0.000000",
        "perpFrozen": "262.500000",
        "predFrozen": "0.000000",
        "mmr": "10.500000",
        "mgnRatio": "0.000084",
        "frozenMgnRatio": "0.002101",
        "accAvgPx": "",
        "spotUpl": "",
        "spotUplRatio": "",
        "entryCost": "",
        "upl": "-150.000000",
        "isoUpl": "0.000000",
        "lastPx": "1.000000",
        "tokenPx": "1.000000",
        "totalLever": "0.016807"
      }
    ],
    "positions": [
      {
        "assetId": "602",
        "assetStatus": "normal",
        "positionSide": "net",
        "marginMode": "cross",
        "leverage": "8",
        "pos": "0.750",
        "avgPx": "3000.000",
        "markPx": "2800.000",
        "positionValue": "2100.000000",
        "upl": "-150.000000",
        "uplRatio": "-0.266667",
        "liqPx": "2650.000",
        "imr": "262.500000",
        "margin": "",
        "mmr": "10.500000",
        "mgnRatio": "0.000084",
        "realizedPnl": "-150.000000",
        "fee": "-1.050000",
        "fundingFee": "0.000000",
        "lastPx": "2801.000",
        "idxPx": "2799.500",
        "quoteUsdPx": "1.000000",
        "pnl": "-150.000000",
        "uplLastPx": "-149.250000",
        "uplRatioLastPx": "-0.265333",
        "closeOrderAlgo": []
      }
    ],
    "trades": []
  }
}

Deduplication Rules#

Data TypeIdentifier Key
TokentokenId
PositionassetId + marginMode + positionSide
TradetradeId

Event-Triggered Full Snapshot of Open Orders exchangeos-orders#

After a successful subscription, the channel immediately pushes a complete snapshot of all open orders for the master account or specified sub-account.

This channel does not push on a fixed schedule. When an Order Event or Fill Event occurs, the system retrieves and pushes a complete snapshot of open orders after the event. It does not push only the orders that changed.

On the initial subscription, or after a subsequent order or fill event, if the account has no open orders, the channel still pushes:

  • orders=[]
  • totalCount="0"
  • activeCount="0"
  • curPage="0"
  • lastPage=true

Subscription Request#

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-orders",
      "vaultAddress": "xxxxx",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Subscription Parameters#

ParameterTypeRequiredDescription
idStringNoUser-defined request ID.
opStringYesFixed value: subscribe.
argsArrayYesSubscription argument list.
> channelStringYesFixed value: exchangeos-orders.
> vaultAddressStringNoSub-account address. Omit to subscribe to the master account.
> pointBoardStringNotrue for the points board and false for the live board. Default: false.
> marketTypesStringNoMarket scope. Supports spot, prediction, and perp. Omit for all markets.

Top-Level Push Fields#

FieldTypeDescription
argObjectEcho of the subscription parameters.
backendStringBackend service that generated this push.
block_heightStringOn-chain block height associated with this snapshot cycle.
block_timestampStringOn-chain block time associated with this snapshot cycle, in Unix milliseconds.
pTimeStringGeneration time of this page's push message, in Unix milliseconds.
userStringMaster-account or sub-account address to which the data belongs.
dataObjectOpen-order snapshot, pagination, and count data for this snapshot cycle.

data Fields#

FieldTypeDescription
typeStringFixed value: snapshot, indicating a complete event-triggered snapshot of open orders.
curPageStringCurrent page number of the snapshot cycle, starting from "0".
lastPageBooleanWhether this is the last page of the snapshot cycle.
totalCountStringTotal number of open orders in the snapshot cycle, including inactive Order-Attached TPSL orders. The value is identical on every page.
activeCountStringTotal number of active orders in the snapshot cycle, excluding inactive Order-Attached TPSL orders. The value is identical on every page.
ordersArrayOpen orders on the current page. Elements can be Order or StopOrder. Returns [] when there are no open orders.

Pagination Rules#

  • type, curPage, lastPage, totalCount, and activeCount are all located inside data.
  • data is an Object. Do not expect the format data: [{ "orders": [] }].
  • All pages in the same snapshot cycle share the same block_height, block_timestamp, totalCount, and activeCount.
  • pTime is the actual generation time of each page. Therefore, pTime can differ across pages.
  • Clients should collect all pages and atomically apply the complete snapshot after receiving lastPage=true.
  • If there are no open orders after an event, the channel still pushes orders=[], totalCount="0", and activeCount="0".

orders[] Element Types#

orders[] returns two flattened data structures:

  • Order: A standard limit order that has entered the order book, or a TP Limit order that has been converted into a standard resting order.
  • StopOrder: A standalone Trigger order, Order-Attached TPSL, or Position-Attached TPSL.

Order-Attached TPSL is not nested in the parent order's attachAlgoOrds[]. It is returned as an independent StopOrder element in the same orders[] array and is linked to its parent order through parentOrderId.

Order Fields#

FieldTypeDescription
oidStringOn-chain order ID.
clientOrderIdStringUser-defined order ID.
assetIdStringProduct ID.
assetStatusStringProduct status: normal, scheduled, converging, or regressing.
sideStringOrder side: buy or sell.
positionSideStringPosition side: net, long, or short. Returns "" for non-perp products.
marginModeStringMargin mode: cross or isolated. Returns "" for non-perp products.
leverageStringLeverage. Only integer leverage is supported. Returns "" when equity is 0 or for non-perp products.
orderTypeStringOrder type. Fixed value: limit.
tifStringTime in force: gtc, ioc, fok, alo, or gtd.
priceStringOrder price.
sizeStringOrder size, in base units.
accFillSzStringCumulative filled size, in base units.
stateStringOrder state, for example open or partially_filled.
reduceOnlyBooleanWhether this is a reduce-only order.
cTimeStringOrder creation time, in Unix milliseconds.
expiresAfterStringOrder expiration time. Returns "" when not applicable.
isMarketBooleanWhether this is a market-execution order.
outcomeReverseBooleanWhether the outcome is reversed.
tpLimitBooleanWhether this is a TP Limit order.

Order does not provide avgPx, parentOrderId, triggerPx, triggerPriceType, triggerCond, tpsl, or attachAlgoOrds.

Calculate the cumulative average fill price through REST GET /trade/fills or the private channel exchangeos-user-fills.

StopOrder Fields#

FieldTypeDescription
oidStringTrigger or TPSL order ID.
assetIdStringProduct ID.
assetStatusStringProduct status: normal, scheduled, converging, or regressing.
sideStringOrder side: buy or sell.
positionSideStringPosition side: net, long, or short. Returns "" for non-perp products.
marginModeStringMargin mode: cross or isolated. Returns "" for non-perp products.
leverageStringLeverage. Only integer leverage is supported. Returns "" when equity is 0 or for non-perp products.
sizeStringTrigger or TPSL order size.
priceStringOrder price for Trigger Limit. Trigger Market returns "".
isMarketBooleanWhether the order executes at market after triggering. true indicates Trigger Market; false indicates Trigger Limit.
reduceOnlyBooleanWhether this is a reduce-only order.
cTimeStringTrigger or TPSL creation time, in Unix milliseconds.
triggerPxStringTrigger price.
triggerPriceTypeStringTrigger price source: mark or index.
triggerCondStringTrigger condition: Gte or Lte.
tpslStringOrder purpose: tp, sl, up, or down.
parentOrderIdStringParent order ID for Order-Attached TPSL. Standalone Trigger and Position-Attached TPSL return "".
isActiveBooleanWhether the order is active. Order-Attached TPSL is false before its parent order reaches a terminal state.
tpLimitBooleanWhether this is a TP Limit order.

StopOrder does not provide clientOrderId, state, accFillSz, or outcomeReverse.

Complete Push Example#

The following example includes one standard perp limit parent order and inactive Order-Attached TP and SL orders. All three items are flattened into data.orders[]. totalCount="3"; only the parent order is active, so activeCount="1".

json
{
  "arg": {
    "channel": "exchangeos-orders",
    "marketTypes": "[\"all\"]",
    "pointBoard": "false"
  },
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "block_height": "42790146",
  "block_timestamp": "1788158619230",
  "data": {
    "activeCount": "1",
    "curPage": "0",
    "lastPage": true,
    "orders": [
      {
        "accFillSz": "0.000",
        "assetId": "602",
        "assetStatus": "normal",
        "cTime": "1788158619200",
        "clientOrderId": "0x030000277b000001a06a12f500000001",
        "expiresAfter": "",
        "isMarket": false,
        "leverage": "10",
        "marginMode": "cross",
        "oid": "117984456",
        "orderType": "limit",
        "outcomeReverse": false,
        "positionSide": "long",
        "price": "38000.000",
        "reduceOnly": false,
        "side": "buy",
        "size": "0.100",
        "state": "open",
        "tif": "gtc",
        "tpLimit": false
      },
      {
        "assetId": "602",
        "assetStatus": "normal",
        "cTime": "1788158619200",
        "isActive": false,
        "isMarket": true,
        "leverage": "10",
        "marginMode": "cross",
        "oid": "117984458",
        "parentOrderId": "117984456",
        "positionSide": "long",
        "price": "",
        "reduceOnly": true,
        "side": "sell",
        "size": "0.100",
        "tpLimit": false,
        "tpsl": "tp",
        "triggerCond": "Gte",
        "triggerPriceType": "mark",
        "triggerPx": "40000.000"
      },
      {
        "assetId": "602",
        "assetStatus": "normal",
        "cTime": "1788158619200",
        "isActive": false,
        "isMarket": true,
        "leverage": "10",
        "marginMode": "cross",
        "oid": "117984459",
        "parentOrderId": "117984456",
        "positionSide": "long",
        "price": "",
        "reduceOnly": true,
        "side": "sell",
        "size": "0.100",
        "tpLimit": false,
        "tpsl": "sl",
        "triggerCond": "Lte",
        "triggerPriceType": "mark",
        "triggerPx": "35000.000"
      }
    ],
    "totalCount": "3",
    "type": "snapshot"
  },
  "pTime": "1788158619303",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb"
}

Empty Order Snapshot Example#

When no open orders remain after an Order Event or Fill Event:

json
{
  "arg": {
    "channel": "exchangeos-orders",
    "marketTypes": "[\"all\"]",
    "pointBoard": "false"
  },
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "block_height": "42790150",
  "block_timestamp": "1788158620000",
  "data": {
    "activeCount": "0",
    "curPage": "0",
    "lastPage": true,
    "orders": [],
    "totalCount": "0",
    "type": "snapshot"
  },
  "pTime": "1788158620080",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb"
}

Setting Updates exchangeos-setting-updates#

An event-triggered channel for account setting updates.

After a successful subscription, the channel does not push a snapshot of the current settings. It pushes an update only when positionMode, roleId, leverage, or marginMode actually changes.

No empty message is pushed when there is no setting change.

This channel does not provide an initial push. The subscription request id can be user-defined.

To subscribe to a sub-account, specify the sub-account address through vaultAddress.

Subscription Request#

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-setting-updates",
      "vaultAddress": "xxxxx",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Subscription Parameters#

ParameterTypeRequiredDescription
idStringNoUser-defined request ID.
opStringYesFixed value: subscribe.
argsArrayYesSubscription argument list.
> channelStringYesFixed value: exchangeos-setting-updates.
> vaultAddressStringNoSub-account address. Omit to subscribe to the master account.
> pointBoardStringNotrue for the points board and false for the live board. Default: false.
> marketTypesStringNoMarket types, for example ["spot", "perp"]. All market types are used when omitted.

Top-Level Push Fields#

FieldTypeDescription
argObjectSubscription information.
> channelStringFixed value: exchangeos-setting-updates.
> vaultAddressStringSub-account address. Omitted when subscribing to the master account.
backendStringBackend service that generated this push.
block_heightStringOn-chain block height associated with this setting change.
block_timestampStringOn-chain block time associated with this setting change, in Unix milliseconds.
pTimeStringActual WebSocket message generation or push time, in Unix milliseconds.
userStringMaster-account or sub-account address to which this update belongs.
dataObjectAccount-level or product-level settings that actually changed.

data Fields#

FieldTypeDescription
accSettingObjectAccount-level setting updates. This field is omitted when no account-level setting has changed.
assetSettingArrayProduct-level setting updates. Returns [] when no product-level setting has changed.

accSetting Fields#

FieldTypeDescription
roleIdStringMargin role ID. Used to apply custom margin rules for special users.
positionModeStringPosition mode. oneWay is one-way mode; hedge is hedge mode.

assetSetting[] Fields#

FieldTypeDescription
assetIdStringContract ID.
positionSideStringPosition side. oneWay mode uses net; hedge mode uses long or short.
leverageStringLeverage. Only integer leverage is supported.
marginModeStringMargin mode: cross for cross margin and isolated for isolated margin.

Example: Updating roleId or positionMode#

json
{
  "arg": {
    "channel": "exchangeos-setting-updates"
  },
  "backend": "okx-defi-tradezone-indexer-pubsub",
  "block_height": "11904367",
  "block_timestamp": "1785897600000",
  "data": {
    "accSetting": {
      "roleId": "3",
      "positionMode": "oneWay"
    },
    "assetSetting": []
  },
  "pTime": "1788158619303",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb"
}

Example: Updating leverage or marginMode#

json
{
  "arg": {
    "channel": "exchangeos-setting-updates"
  },
  "block_height": "95616486",
  "block_timestamp": "1785897600000",
  "pTime": "1788158619303",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "assetSetting": [
      {
        "assetId": "202",
        "positionSide": "long",
        "leverage": "10",
        "marginMode": "isolated"
      },
      {
        "assetId": "202",
        "positionSide": "short",
        "leverage": "20",
        "marginMode": "isolated"
      }
    ]
  },
  "backend": "okx-defi-tradezone-indexer-pubsub"
}

User Order Status exchangeos-user-order-status#

Pushes order-submission results and subsequent state changes. Historical orders are not pushed. A rejected order is pushed even if no oid was created; its oid is "".

The payload is directly data: OrderDetail[]. It does not use orderStatuses[] or an order wrapper. Results from batch requests are emitted in input order.

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-user-order-status",
      "vaultAddress": "0x...",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Subscription Parameters#

ParameterTypeRequiredDescription
channelStringYesMust be exchangeos-user-order-status.
vaultAddressStringNoSubaccount address. Omit it to subscribe to the master account.
pointBoardStringNo"true" for point board and "false" for live trading. Defaults to "false".
marketTypesStringNoJSON Array string. May include spot, prediction, and perp. Omit it for all markets.

data[]: OrderDetail Fields#

FieldTypeDescription
oidStringOrder ID; "" if a rejected order was never created.
clientOrderIdStringClient order ID.
assetIdStringProduct ID.
marketTypeStringMarket type, such as spot, prediction, or perp.
stateStringOrder state; see the table below.
cancelReasonStringCancellation or rejection reason; empty when absent.
cTimeStringOrder creation time in Unix epoch milliseconds.
marginModeStringcross or isolated.
positionSideStringnet, long, or short.
sideStringbuy or sell.
priceStringOrder price.
sizeStringOrder size.
sizeTypeStringSize unit, such as base or quote.
accFillSzStringCumulative filled size.
reduceOnlyBooleanWhether the order is reduce-only.
outcomeReverseBooleanWhether the order is outcome-reverse.
parentOrderIdStringParent order ID; empty if not applicable.
tifStringTime-in-force, such as gtc or ioc.
triggerInfoObjectTrigger-order or TPSL information; absent for ordinary orders.
childrenArrayRelated child orders created after triggering; may be absent.

side and positionSide#

Business DirectionsidepositionSide
Buy / one-way modebuynet
Sell / one-way modesellnet
Open Longbuylong
Close Longselllong
Open Shortsellshort
Close Shortbuyshort

state Enumeration#

ValueMeaningDescription
openOrder openedThe order entered the order book or was successfully created.
canceledOrder canceledCheck cancelReason for the specific reason.
rejectedOrder rejectedPlacement or trigger execution failed; an oid may not have been created.
filledOrder filledThe order was fully filled and reached a terminal state.
modifiedOrder modified in placeThe order retains its oid, typically for a same-price size reduction.
triggeredTrigger order triggeredThe trigger condition was met; created order IDs are returned through children.
activeConditional order activatedAn Order-Attached TPSL child order became active after its parent order filled.

cancelReason Enumeration#

cancelReasonMeaning
iocNoFillAn IOC order found no executable liquidity.
fokNotFilledAn FOK order could not be fully filled.
aloRejectedAn ALO / post-only order would execute immediately and was rejected.
userCancelUser-initiated cancellation.
selfTradeCancelCancellation caused by self-trade prevention.
expiredA GTD order expired.
makerInsufficientBalanceCancellation caused by insufficient maker balance.
clearOrderBookCancellation caused by order-book clearing.
userModifyCancellation or re-posting caused by a user order modification.
reduceOnlyTrimOrder quantity was reduced by a reduce-only constraint.
marginInsufficientInsufficient margin caused rejection or cancellation of the remaining quantity.
assetHaltedThe asset was halted or delisted.
relatedPositionClosedThe related position was closed or reversed.
parentOrderCanceledA related child order was canceled because its parent order terminated unfilled.
marginTierExceededThe position-tier limit was exceeded.
triggerShrunkToZeroThe executable trigger quantity became zero after limit trimming.
triggerPriceOutOfBandThe post-trigger limit price fell outside the price-protection band.
tpLimitActivationInvariantViolatedExecution prerequisites, such as position mode, changed when TP Limit activation occurred.
sizeDecimalsAdjustA size-decimal adjustment truncated the order quantity.
priceDecimalsAdjustA price-decimal adjustment canceled the order.
priceDecimalsAdjustModifyA price-decimal adjustment modified the surviving order in place.

Push Example#

json
{
  "arg": {
    "channel": "exchangeos-user-order-status",
    "marketTypes": "[\"perp\"]",
    "pointBoard": "true"
  },
  "backend": "okx-defi-tradezone-indexer-pubsub-pre",
  "block_height": "148342375",
  "block_timestamp": "1791195529876",
  "data": {
    "orderStatuses": [
      {
        "order": {
          "accFillSz": "0.000",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x03328ef1b810936f92a04d7cb4ad775b",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928539",
          "outcomeReverse": false,
          "positionSide": "net",
          "price": "119.800",
          "reduceOnly": false,
          "side": "buy",
          "size": "0.080",
          "sizeType": "base",
          "tif": "gtc"
        },
        "state": "open"
      },
      {
        "order": {
          "accFillSz": "0.080",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x03328ef1b810936f92a04d7cb4ad775b",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928539",
          "outcomeReverse": false,
          "positionSide": "net",
          "price": "119.800",
          "reduceOnly": false,
          "side": "buy",
          "size": "0.080",
          "sizeType": "base",
          "tif": "gtc"
        },
        "state": "filled"
      },
      {
        "order": {
          "accFillSz": "0.000",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x0397153bdc7272bb7bc8bf49769e1ae4",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928540",
          "outcomeReverse": false,
          "parentOrderId": "107928539",
          "positionSide": "net",
          "price": "0.000",
          "reduceOnly": true,
          "side": "sell",
          "size": "0.000",
          "sizeType": "base",
          "tif": "ioc",
          "triggerInfo": {
            "isMarket": true,
            "parentOrderId": "107928539",
            "triggerPriceType": "mark",
            "triggerPx": "130.000",
            "triggerType": "tp"
          }
        },
        "state": "open"
      },
      {
        "order": {
          "accFillSz": "0.000",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x0371963d1dcc395160419fc0d51b0d0c",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928541",
          "outcomeReverse": false,
          "parentOrderId": "107928539",
          "positionSide": "net",
          "price": "0.000",
          "reduceOnly": true,
          "side": "sell",
          "size": "0.000",
          "sizeType": "base",
          "tif": "ioc",
          "triggerInfo": {
            "isMarket": true,
            "parentOrderId": "107928539",
            "triggerPriceType": "mark",
            "triggerPx": "80.000",
            "triggerType": "sl"
          }
        },
        "state": "open"
      },
      {
        "order": {
          "accFillSz": "0.000",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x0397153bdc7272bb7bc8bf49769e1ae4",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928540",
          "outcomeReverse": false,
          "parentOrderId": "107928539",
          "positionSide": "net",
          "price": "0.000",
          "reduceOnly": true,
          "side": "sell",
          "size": "0.080",
          "sizeType": "base",
          "tif": "ioc",
          "triggerInfo": {
            "isMarket": true,
            "parentOrderId": "107928539",
            "triggerPriceType": "mark",
            "triggerPx": "130.000",
            "triggerType": "tp"
          }
        },
        "state": "active"
      },
      {
        "order": {
          "accFillSz": "0.000",
          "assetId": "302",
          "cTime": "1791195529876",
          "clientOrderId": "0x0371963d1dcc395160419fc0d51b0d0c",
          "marginMode": "cross",
          "marketType": "perp",
          "oid": "107928541",
          "outcomeReverse": false,
          "parentOrderId": "107928539",
          "positionSide": "net",
          "price": "0.000",
          "reduceOnly": true,
          "side": "sell",
          "size": "0.080",
          "sizeType": "base",
          "tif": "ioc",
          "triggerInfo": {
            "isMarket": true,
            "parentOrderId": "107928539",
            "triggerPriceType": "mark",
            "triggerPx": "80.000",
            "triggerType": "sl"
          }
        },
        "state": "active"
      }
    ]
  },
  "pTime": "1791195529910",
  "user": "0x11bb62db5379b5c79ff996e69b88b8175c49f4fe"
}

User Fills exchangeos-user-fills#

Pushes new fills after subscription only. It sends no initial historical snapshot.

  • The channel does not paginate. Use data.fills[] length for the number of fills in a push.
  • Use REST GET /trade/fills to recover historical or disconnected-period fills.
  • Subscribe first and buffer events, then retrieve REST history and merge/deduplicate by tradeId.
  • Normal matching fills are uniquely identified by non-empty tradeId.
  • Liquidation, ADL, and settlement fills can return tradeId: ""; empty trade IDs must not all be treated as the same fill.
  • The outer block_timestamp is the blockchain-data time for the batch. Multiple fills can share it and must not overwrite one another.
json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-user-fills",
      "vaultAddress": "0x...",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Fill Push Fields#

FieldTypeDescription
argObjectEchoed subscription conditions.
backendStringBackend service that generated the push.
block_heightStringBatch blockchain block height.
block_timestampStringBatch blockchain-data time.
pTimeStringPush-generation time; not used for fill deduplication.
userStringAssociated master-account or subaccount address.
data.fillsArray of ObjectFill array; a batch can contain multiple fills.

data.fills[] Fields#

FieldTypeDescription
tradeIdStringNormal matching fill ID; "" for applicable system fills.
oidStringOn-chain order ID that produced the fill; "" when inapplicable.
clientOrderIdStringClient order ID; "" when unset or inapplicable.
assetIdStringProduct ID.
marketTypeObjectMarket and trading attributes. Perp contains marginMode and positionSide; spot and Prediction return their own market objects.
sideStringbuy or sell.
execTypeStringmaker or taker.
priceStringFill price.
sizeStringFill size.
sizeTypeStringbase or quote.
remainingSizeStringRemaining order size after the fill.
feeStringNon-negative fee amount; "0" if none.
feeTokenIdStringFee token ID; "" when inapplicable.
rebateStringNon-negative rebate amount; "0" if none.
rebateTokenStringRebate token ID; "" if none.
oppositeOrderIdStringCounterparty order oid.
oppositeUserStringCounterparty address.
pnlStringRealized PnL for the fill; "" for spot or when inapplicable.
fillDirStringDetailed fill direction.
startPositionStringPre-match position quantity or spot asset balance.
twapIdStringParent TWAP ID; "" for non-TWAP fills.

FillDir Enumeration#

ValueMeaning
Buy / SellBuyer or seller fill from ordinary matching or Prediction Market transfer settlement.
BuySplit / SellMergeImplicit Prediction Market split or merge.
BackstopLiquidation / BackstopLiquidatorInsurance-fund liquidation takeover and fund-side view.
Adl / AdlOpponentADL event and its counterparty view.
AdlPreviousPrice / AdlOpponentPreviousPriceADL event valued using a prior price.
NetLiquidation / NetAdlNet liquidation or net ADL.
SettlementSettlement fill.
Open / ClosePerpetual opening or reducing/closing fill.
ReverseOpenA single fill crosses zero: closes the original position, then opens the opposite position.
DecimalAdjustSettle / DecimalAdjustTakeoverPre-release decimal-adjustment values; not emitted by the current version.

Push Example#

json
{
  "arg": {
    "channel": "exchangeos-user-fills",
    "marketTypes": "[\"spot\", \"perp\"]",
    "pointBoard": "false"
  },
  "backend": "okx-defi-tradezone-indexerpubsub-awstky-pro",
  "block_height": "12092417",
  "block_timestamp": "1785218400074",
  "pTime": "1785218400150",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "fills": [
      {
        "tradeId": "780",
        "oid": "90005",
        "clientOrderId": "",
        "assetId": "602",
        "marketType": {
          "perp": {
            "marginMode": "isolated",
            "positionSide": "long"
          }
        },
        "side": "sell",
        "execType": "taker",
        "price": "2895",
        "size": "1.5",
        "sizeType": "base",
        "remainingSize": "0",
        "fee": "1.085625",
        "feeTokenId": "0",
        "rebate": "0",
        "rebateToken": "",
        "oppositeOrderId": "",
        "oppositeUser": "",
        "pnl": "-157.5",
        "fillDir": "Sell",
        "startPosition": "1.5",
        "twapId": ""
      }
    ]
  }
}

User Fundings exchangeos-user-fundings#

An incremental funding-fee event channel. It sends no initial snapshot, no empty snapshot, and no historical funding events. It pushes only when funding is actually charged or paid. Push frequency follows the product settlementInterval; it is not fixed hourly.

Recover historical or missed funding events through:

text
GET /account/bills?billType=funding_fee
json
{
  "id": "123",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-user-fundings",
      "vaultAddress": "0x...",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

data.fundings[] Fields#

FieldTypeDescription
assetIdStringContract ID.
fundingFeeStringNegative means paid; positive means received.
posStringPosition quantity.
fundingRateStringFunding rate.
marginModeStringcross or isolated.
positionSideStringnet, short, or long.

Push Example#

json
{
  "arg": {
    "channel": "exchangeos-user-fundings"
  },
  "backend": "okx-defi-tradezone-indexer-pubsub",
  "block_height": "13451456",
  "block_timestamp": "1785218400074",
  "pTime": "1788158619303",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "fundings": [
      {
        "assetId": "602",
        "fundingFee": "-45",
        "fundingRate": "-0.015",
        "marginMode": "cross",
        "positionSide": "short",
        "pos": "-1.5"
      }
    ]
  }
}

User Ledger Updates exchangeos-user-ledger-updates#

Pushes non-funding ledger changes, including deposits, withdrawals, account transfers, subaccount transfers, liquidations, Vault operations, Prediction Market operations, isolated-margin transfers, and margin-mode changes.

Funding events are not pushed by this channel; use exchangeos-user-fundings.

json
{
  "id": "req001",
  "op": "subscribe",
  "args": [
    {
      "channel": "exchangeos-user-ledger-updates",
      "vaultAddress": "0x...",
      "pointBoard": "false",
      "marketTypes": "[\"spot\", \"perp\"]"
    }
  ]
}

Push Rules#

  • This is an event-only channel and does not send a historical initial snapshot.
  • Each WebSocket message is a JSON object, not a [{...}] array.
  • The business payload is always data: { "ledgerUpdates": [...] }.
  • Every ledgerUpdates[] item contains time, hash, and delta.
  • Every delta contains affected users[] and exactly one concrete event variant.
  • Determine event type from the variant key; do not rely on field count or field order.
  • block_timestamp is the batch block time, ledgerUpdates[].time is the individual event time, and pTime is the push-generation time. Do not interchange them.

data.ledgerUpdates[] Fields#

FieldTypeDescription
timeStringIndividual ledger-event time in Unix epoch milliseconds.
hashStringRelated transaction or event hash.
deltaObjectLedger-change payload.
delta.usersArray of StringAffected account addresses.
delta.<variant>ObjectExactly one concrete ledger-event object.

delta Variants#

VariantDescription
liquidationPenalityCompensationEventLiquidation penalty and compensation. Penality is the existing wire-key spelling and must be parsed exactly.
transferTransfer across account or market ledgers.
subAccountTransferTransfer between master account and subaccount.
depositDeposit from X Layer.
withdrawWithdrawal to X Layer.
vaultCreateVault creation.
vaultDepositDeposit to a Vault.
vaultWithdrawWithdrawal from a Vault.
vaultDistributionVault profit distribution.
vaultLeaderCommissionVault leader commission.
predictionSplitPrediction Market split.
predictionMergePrediction Market merge.
predictionRedeemPrediction Market settlement redemption.
predictionConvertPrediction Market negRisk conversion.
depositAndRedeemDeposit and automatic redemption of a settled Prediction Market token.
tokenBurnUser-balance change caused by a total token burn.
actionPurchaseFeeFee for purchasing Action Allowance.
isolatedMarginTransferMargin transfer between cross account and isolated position.
updateMarginModeCross / isolated mode change and related collateral movement.

Documented Variant Fields#

transfer#

FieldTypeDescription
userStringSource account.
destinationStringDestination account.
sourceDex / destinationDexStringSource and destination business lines, such as perp and spot.
tokenIdStringToken ID.
amountStringTransfer amount.
feeStringTransfer fee.

updateMarginMode#

FieldTypeDescription
userStringAccount address.
assetIdStringProduct ID.
marginModeStringUpdated margin mode.
movesArrayMargin-movement entries.
moves[].sideStringPosition side.
moves[].amountStringMoved amount.

liquidationPenalityCompensationEvent#

FieldTypeDescription
marginModeStringMargin mode.
fullTakeOverBooleanWhether the position was fully taken over.
liquidatorItemsObjectLiquidation items keyed by liquidator address.
chargeListArrayLiquidation penalty and compensation entries.
chargeList[].assetIdStringProduct ID.
chargeList[].positionSideStringPosition side.
chargeList[].penalityStringLiquidation penalty; this is the existing wire-key spelling.
chargeList[].feeStringFee.
chargeList[].wearingCompensationStringCompensation amount.
chargeList[].isLongPositionBooleanWhether the position is long.
chargeList[].takeoverSizeStringTakeover size.
chargeList[].takeoverPriceStringTakeover price.

Push Example#

json
{
  "arg": {
    "channel": "exchangeos-user-ledger-updates"
  },
  "backend": "okx-defi-tradezone-indexer-pubsub",
  "block_height": "13451456",
  "block_timestamp": "1785218400074",
  "pTime": "1785218400150",
  "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
  "data": {
    "ledgerUpdates": [
      {
        "time": "1785218400068",
        "hash": "0x8c76a11353098545b176cc04214c06fa3758b4574ce4f7aa3762d4565afae821",
        "delta": {
          "users": [
            "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
            "0x93f51fc5190b1e7bb82238bcc2f93430b43a9243"
          ],
          "transfer": {
            "user": "0x2e988a386a799f506693793c6a5af6b54dfaabfb",
            "destination": "0x93f51fc5190b1e7bb82238bcc2f93430b43a9243",
            "sourceDex": "perp",
            "destinationDex": "spot",
            "tokenId": "0",
            "amount": "500",
            "fee": "0.1"
          }
        }
      }
    ]
  }
}
Table of contents