REST API (Public & Private Endpoints)

Introduction

The Open Trade REST API is a request/response counterpart to the WebSocket API. Every endpoint here is a direct REST equivalent of a WebSocket channel or command — if you'd rather poll or fire one-off requests instead of holding a persistent socket open, this is the interface to use.

REST vs. WebSocket Use the Market Data API and Private Data API (WebSocket) for real-time streaming subscriptions. Use this REST API for one-shot reads and order actions where a persistent connection isn't needed. Both interfaces share the same underlying authentication flow.

REST Base URL

PROD: https://gateway-public.opentrade.exchange
UAT: https://gateway-public-uat.opentrade.exchange
The URL above is the host only. Each endpoint below shows its complete path, e.g. /hermes-ws-gateway/api/rest/balance — concatenate host + that full path.

Endpoint Groups

Authentication is required on every endpoint Swagger labels the endpoints below as "public" (no `/public/` path segment vs. `/trade-private/`), reflecting their original design intent. In practice, this gateway requires a valid Bearer token on every route, including the ones under /public/. Send the Authorization header on all requests below.
/public/ path (market data, no account-specific data)
  • GET /public/asset-list
  • GET /public/instrument-list
  • GET /public/order-book-public
/trade-private/ path and account endpoints (account/order data)
  • POST / PUT / DELETE /trade-private/orders
  • GET /trade-private/trades-history
  • GET /trade-private/orders-history
  • GET /trade-private/active-orders
  • GET /client-portfolio
  • GET /client-portfolio-history
  • GET /balance

Versioning & Headers

Every REST call — public or private — must include the X-API-Version header. This lets Open Trade evolve the REST contract without breaking existing integrations.

HeaderRequiredDescription
X-API-Version Yes API version to target. Current value: 1.0.0
Authorization Private only Bearer JWT token, obtained via the authentication flow below. Required on every private endpoint.

Authentication

Private REST endpoints use the exact same credential exchange as the Private Data API (WebSocket) — obtain your JWT once, then reuse it across both interfaces.

Authentication Steps
  1. Login with username and password to obtain a session cookie
  2. Use the session cookie to obtain a JWT token
  3. Send the JWT token as a Bearer token in the Authorization header of every private REST request

Authentication Flow

Step 1: Login with Username and Password

Using POST method, send your credentials to the login endpoint. Note that the credentials must be sent as form-data with keys in lowercase. This returns a SESSION cookie (not JSESSIONID).

Login Endpoints
// UAT Environment
POST https://auth-uat.opentrade.exchange/login

// PROD Environment
POST https://auth.opentrade.exchange/login

// Form Data (lowercase keys!)
username: your_username
password: your_password
Important! The username and password keys MUST be in lowercase. After successful login (HTTP 200 or 302), you will receive a SESSION cookie that you need for the next step.

Step 2: Obtain JWT Token

Use the SESSION cookie from Step 1 to obtain your JWT token. This is a POST with the client secret sent as a header, not a query parameter, and an empty body.

Token Endpoints
// UAT Environment
POST https://auth-uat.opentrade.exchange/auth/jwt/clients/{client-api-username}/token

// PROD Environment
POST https://auth.opentrade.exchange/auth/jwt/clients/{client-api-username}/token

// Headers
Cookie: SESSION={session_cookie_from_step_1}
clientSecret: {secret}

// Body: empty
Note the plural The path is /auth/jwt/clients/ (plural) — not /client/. And note this is a single /auth/, not the doubled /auth/auth/ some older references show.

Complete Authentication Flow with cURL

cURL Example
curl -s --cookie-jar cookies.txt -X POST \
    "https://auth-uat.opentrade.exchange/login" \
    -d "username=[USER_NAME]&password=[USER_PASSWORD]" \
    --next -s -b cookies.txt -X POST \
    "https://auth-uat.opentrade.exchange/auth/jwt/clients/[API_USER_NAME]/token" \
    -H "accept: */*" \
    -H "clientSecret: [API_SECRET]" \
    -d ""
Success! The response body is your token, already prefixed: Bearer eyJ.... Use it as-is in the Authorization header — don't add a second "Bearer " prefix. The response also includes a jwt-expire-at header (token lifetime) and jwt-scope header.

Using Your Token

The token returned from the authentication flow already includes the Bearer prefix (the response body reads Bearer eyJ...). Use it exactly as returned in the Authorization header — do not prepend a second Bearer , or the header will read Bearer Bearer eyJ... and be rejected.

Include it on every private REST call, alongside the required X-API-Version header.

Example Authenticated Request
GET /hermes-ws-gateway/api/rest/trade-private/active-orders HTTP/1.1
Host: gateway-public-uat.opentrade.exchange
X-API-Version: 1.0.0
Authorization: Bearer eyJraWQiOiIwYWJmMGYwZS00YzliLTQ3NjItYjkxYS04NjE2YzkxMzJkMjkiLCJhbGciOiJSUzI1NiJ9...

Token Lifetime

The token response includes two headers you should read and store alongside the token itself:

HeaderDescription
jwt-expire-atISO-8601 timestamp of when the token expires. Re-run the login + token exchange before this time to get a fresh token.
jwt-scopeScope granted to this token, e.g. api.access.
Token Management Tips:
  • Store your token securely and never expose it in client-side code
  • Read jwt-expire-at from the token response and refresh proactively before that time, rather than waiting for a 401
  • Re-running the full login + token exchange is how you refresh — there is no separate refresh-token endpoint
  • Use environment variables or a secrets manager to store credentials, never hardcode them in source control
GET /hermes-ws-gateway/api/rest/public/asset-list Auth Required Asset List

REST equivalent of the WS ASSET_LIST channel. Returns the full list of assets supported across all connected exchanges.

Headers

NameInTypeRequiredDescription
Authorization header string Yes Bearer JWT token
X-API-Version header string Optional Default: 1.0.0
200 Response
[
    {
        "class": "Currency",
        "code": "BTC",
        "name": "BTC"
    }
]
GET /hermes-ws-gateway/api/rest/public/instrument-list Auth Required Instrument List

REST equivalent of the WS INSTRUMENT_LIST channel. Returns all tradable instruments (pairs) and their quote currency.

Headers

NameInTypeRequiredDescription
Authorization header string Yes Bearer JWT token
X-API-Version header string Optional Default: 1.0.0
200 Response
[
    {
        "class": "Instrument",
        "quoteCurrencyCode": "BTC",
        "code": "BTC/USD",
        "name": "BTC/USD"
    }
]
GET /hermes-ws-gateway/api/rest/public/order-book-public Auth Required Order Book

REST equivalent of a WS ORDER_BOOK_PUBLIC channel GET snapshot. Returns an L2 order book snapshot (bids/asks) for the requested instrument(s).

Query Parameters

NameInTypeRequiredDescription
instruments query array<string> Yes Instrument codes to fetch, e.g. BTC/USD
Authorization header string Yes Bearer JWT token
X-API-Version header string Optional Default: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/public/order-book-public?instruments=BTC/USD HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
[
    {
        "class": "OrderBook",
        "exchange": "OKEX",
        "symbol": "BTC/USDT",
        "bids": [
            [63985.5, 0.50735545]
        ],
        "asks": [
            [63985.6, 1.08926571]
        ],
        "eventTime": 1783442361532
    }
]
bids / asks format Each entry is a [price, amount] pair, ordered best-price-first. eventTime is a Unix epoch timestamp in milliseconds. The response returns one entry per exchange with liquidity for the requested instrument — expect multiple entries per instrument (e.g. one each for OKEX, BITGET, HUOBI), not a single merged book.
POST /hermes-ws-gateway/api/rest/trade-private/orders Auth Required Create Orders

REST equivalent of the WS TRADE_PRIVATE channel CREATE command. Accepts an array so multiple orders can be submitted in a single call.

Headers

NameInTypeRequiredDescription
Authorization header string Yes Bearer JWT token
X-API-Version header string Optional Default: 1.0.0

Request Body

FieldTypeRequiredDescription
exchangestringOptionalName of exchange to send order to, such as BITFINEX, LMAX, OKX. If not provided, order will be set as SMART
globalInstrumentCdstringYesInstrument code, e.g. BTC/USD
clientOrderIdstringOptionalRecommend unique Unix timestamp; server will assign one if omitted
directionstringYesBUY or SELL
orderTypestringYesMARKET, LIMIT, POST_ONLY, BUY_STOP, SELL_STOP, STOP_LOSS, TAKE_PROFIT
timeInForcestringOptionalGTC, GTD, GTT, FOK, IOC
pricenumberYesPrice required always
amountnumberYesOrder quantity
Request Body
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "direction": "SELL",
        "orderType": "LIMIT",
        "timeInForce": "GTC",
        "price": 0.215,
        "amount": 1.0
    }
]
200 Response
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "direction": "SELL",
        "orderType": "LIMIT",
        "timeInForce": "GTC",
        "price": 0.215,
        "amount": 1.0,
        "orderStatus": "NEW",
        "exchangeOrderId": "1928374650",
        "filledPrice": 0.0,
        "filledAmount": 0.0,
        "orderDateTime": "2026-07-07T13:04:43.792Z",
        "message": "",
        "processInstanceId": "string"
    }
]
Critical! clientOrderId must be unique per order. Reusing an ID will be rejected.
PUT /hermes-ws-gateway/api/rest/trade-private/orders Auth Required Update Orders

REST equivalent of the WS TRADE_PRIVATE channel UPDATE command (order modification — e.g. price/amount changes on a resting order).

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

Uses the same request/response body shape as Create Orders, but requires an existing clientOrderId or exchangeOrderId to identify the order being modified.

Request Body
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "direction": "SELL",
        "orderType": "LIMIT",
        "timeInForce": "GTC",
        "price": 0.22,
        "amount": 1.0
    }
]
DELETE /hermes-ws-gateway/api/rest/trade-private/orders Auth Required Cancel Orders

REST equivalent of the WS TRADE_PRIVATE channel CANCEL command.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

Note that DELETE requests here carry a request body — identify the order(s) to cancel via clientOrderId, exchangeOrderId, and globalInstrumentCd.

Cancel resolution rules
  • You must provide either clientOrderId or exchangeOrderId — at least one is required to identify the order.
  • If clientOrderId is provided, it is used (takes precedence over exchangeOrderId).
  • If only exchangeOrderId is provided, that order is cancelled.
  • If neither is provided, all orders for the selected pair(s) will be cancelled.
Request Body
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "exchangeOrderId": "1928374650"
    }
]
200 Response
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "orderStatus": "CANCELLED",
        "exchangeOrderId": "1928374650",
        "orderDateTime": "2026-07-07T13:04:52.249Z",
        "message": ""
    }
]
GET /hermes-ws-gateway/api/rest/trade-private/active-orders Auth Required Active Orders

REST equivalent of the WS TRADE_PRIVATE channel active orders GET. Returns all currently open (not filled/cancelled/rejected) orders.

Query Parameters

NameInTypeRequiredDescription
instrumentsqueryarray<string>OptionalFilter to specific instruments; omit for all
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
200 Response
[
    {
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USD",
        "clientOrderId": "0989876565",
        "direction": "SELL",
        "orderType": "LIMIT",
        "timeInForce": "GTC",
        "price": 0.215,
        "amount": 1.0,
        "orderStatus": "ACTIVE",
        "exchangeOrderId": "1928374650",
        "filledPrice": 0.0,
        "filledAmount": 0.0,
        "orderDateTime": "2026-07-07T13:06:29.441Z",
        "message": "",
        "processInstanceId": "string"
    }
]
GET /hermes-ws-gateway/api/rest/trade-private/trades-history Auth Required Trades History

REST equivalent of the WS TRADE_PRIVATE channel trades history GET. Returns executed trades (fills) within a date range.

Query Parameters

NameInTypeRequiredDescription
instrumentsqueryarray<string>OptionalFilter to specific instruments
fromDtmquerystring ($date-time)OptionalRange start (ISO-8601)
toDtmquerystring ($date-time)OptionalRange end (ISO-8601)
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/trade-private/trades-history?instruments=BTC/USDT&fromDtm=2026-06-01T00:00:00&toDtm=2026-07-01T00:00:00 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
[
    {
        "class": "Order",
        "exchange": "OKEX",
        "globalInstrumentCd": "BTC/USDT",
        "clientOrderId": "11781606906612",
        "direction": "BUY",
        "orderType": "MARKET",
        "timeInForce": "GTC",
        "price": 66591.4,
        "amount": 0.0002,
        "orderStatus": "FILLED",
        "exchangeOrderId": "3660939752535318528",
        "filledPrice": 66558.0,
        "filledAmount": 0.0002,
        "orderDateTime": "2026-06-16T10:48:26.747Z",
        "message": null,
        "processInstanceId": null
    }
]
Partial fills An order that fills across multiple executions appears as multiple rows sharing the same clientOrderId, one per fill (e.g. PARTIALLY_FILLED followed by FILLED). Aggregate by clientOrderId if you need one row per order rather than per fill.
GET /hermes-ws-gateway/api/rest/trade-private/orders-history Auth Required Orders History

REST equivalent of the WS TRADE_PRIVATE channel orders history GET. Returns historical orders filtered by status and date range.

Query Parameters

NameInTypeRequiredDescription
instrumentsqueryarray<string>YesInstrument codes to filter by
statusesqueryarray<string>YesSee status values below
fromDtmquerystring ($date-time)OptionalRange start (ISO-8601)
toDtmquerystring ($date-time)OptionalRange end (ISO-8601)
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

Available Status Values

NEW, SUBMITTED, PENDING, ACTIVE, IN_RECONCILIATION, PARTIALLY_FILLED, FILLED, CANCELLED, REJECTED, EXPIRED, FAILED, REJECTED_WRONG_ENV, DUPLICATE, UNKNOWN

GET /hermes-ws-gateway/api/rest/client-portfolio Auth Required Client Portfolio

REST equivalent of the WS CLIENT_PORTFOLIO channel GET snapshot. Returns current holdings by asset type, including exposure, PnL, and available balances.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
200 Response
[
    {
        "class": "ClientPortfolio",
        "assetType": "BTC",
        "quantity": 0.0019553,
        "wap": 90550.7416782,
        "index": 88010.42919245128,
        "onOrders": 0.0,
        "available": 0.0019553,
        "marketValue": 172.0867922,
        "unrealizedPnl": -51.7776368,
        "notional": 177.05386520338445
    }
]

wap is the weighted average price (your cost basis) for the position; index is the current mark price used for valuation. unrealizedPnl reflects the difference between the two and can be negative. quantity and available can be negative for a short position.

GET /hermes-ws-gateway/api/rest/client-portfolio-history Auth Required Client Portfolio History

Historical counterpart to Client Portfolio — returns portfolio snapshots over a date range instead of the live snapshot.

Full reference coming soon Detailed parameter and response documentation for this endpoint is being finalized. Contact API support for the current schema.
GET /hermes-ws-gateway/api/rest/balance Auth Required Balance

REST equivalent of the WS BALANCE channel. Returns account balances by currency.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
200 Response
[
    {
        "class": "Balance",
        "currencyCode": "BTC",
        "balance": 0.0019553,
        "available": 0.0019553,
        "locked": 0.0
    }
]

balance is total holdings for that currency; available is free/withdrawable; locked is held against open orders (balance = available + locked).

GET /hermes-ws-gateway/api/rest/client-balance-distribution Auth Required Balance Distribution

REST equivalent of the WS CLIENT_BALANCE_DISTRIBUTION channel GET. Returns where your tokens actually sit: one row per asset per venue, with cost basis, valuation and PnL for that venue.

Why this is not the same as Balance /balance and /client-portfolio both report the aggregate across every venue, but an order is routed to exactly one exchange and is checked against that venue's balance alone. Read this endpoint to decide where an order can actually be filled, and how much can be withdrawn or transferred off a given venue.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

There are no query parameters. The client is taken from the token, so there is no way to request another account's distribution.

200 Response
[
    {
        "class": "ClientBalanceDistribution",
        "clientId": 1000123,
        "asset": "BTC",
        "exchange": "OKEX",
        "finalBalance": 0.35,
        "costBasisUsd": 30642.7595,
        "totalValueUsd": 30803.6502,
        "inventoryValueUsd": 30642.7595,
        "wap": 87550.7414,
        "lockedAmount": 0.05,
        "availableAmount": 0.3,
        "unrealizedPnl": 160.8907,
        "returnPercent": 0.525
    },
    {
        "class": "ClientBalanceDistribution",
        "clientId": 1000123,
        "asset": "BTC",
        "exchange": "BITGET",
        "finalBalance": 0.12,
        "costBasisUsd": 10866.089,
        "totalValueUsd": 10561.2515,
        "inventoryValueUsd": 10866.089,
        "wap": 90550.7417,
        "lockedAmount": 0.0,
        "availableAmount": 0.12,
        "unrealizedPnl": -304.8375,
        "returnPercent": -2.8054
    }
]

Response Fields

FieldTypeDescription
clientIdnumberYour Open Trade client identifier, taken from the token.
assetstringAsset code, e.g. BTC, USDT, GALA.
exchangestringVenue holding the asset: OKEX, HUOBI, BITGET, BITMART, BINANCE, DERIBIT, LMAX, GEMINI, BLOCKCHAIN, OPENTRADE.
finalBalancenumberTotal amount of the asset held on that venue.
availableAmountnumberAmount free to trade, withdraw or transfer from that venue.
lockedAmountnumberAmount reserved on that venue, typically against open orders or a pending transfer.
wapnumberWeighted average price paid for the holding on that venue, in USD.
costBasisUsdnumberUSD cost basis of the holding on that venue.
inventoryValueUsdnumberUSD value of the inventory carried for the position on that venue.
totalValueUsdnumberCurrent USD market value of the holding on that venue.
unrealizedPnlnumberUnrealized PnL on the holding, in USD. Negative when the position is under water.
returnPercentnumberReturn on the holding, in percent.

An asset held on three exchanges comes back as three rows. Sum finalBalance over the rows sharing an asset to reconcile against /balance, and never assume a single row carries the whole position.

Same rows as the WebSocket channel These are the objects the CLIENT_BALANCE_DISTRIBUTION channel returns, carrying the same "class" discriminator. Only the envelope differs: the WS message wraps them in a data array, while REST returns the array on its own.
GET /hermes-ws-gateway/api/rest/deposit-wallet Auth Required Deposit Wallets

REST equivalent of the WS DEPOSIT_WALLET channel. Returns the client's deposit wallet addresses, one per supported asset.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
200 Response
[
    {
        "class": "DepositWallet",
        "id": 1000003606,
        "clientId": 100882,
        "symbol": "XRP",
        "walletAddress": "rnSffMjADGXG9apHR6gjKz8THc1FtZGCov",
        "status": "ACTIVE",
        "comment": "tag: 1000003606",
        "exchange": "OPENTRADE"
    },
    {
        "class": "DepositWallet",
        "id": 1000003615,
        "clientId": 100882,
        "symbol": "AAVE",
        "walletAddress": "0x649590c78f702ed0cdeab07daf722673d2510afe",
        "status": "ACTIVE",
        "comment": null,
        "exchange": "OPENTRADE"
    }
]

comment carries the destination tag/memo when the asset requires one (e.g. XRP); otherwise null.

GET /hermes-ws-gateway/api/rest/deposit-workflow Auth Required Deposit Workflow

REST equivalent of the WS DEPOSIT_WORKFLOW channel GET. Tracks the lifecycle of incoming on-chain deposits as they are detected, confirmed, and credited to your account.

Query Parameters

NameInTypeRequiredDescription
categoryquerystringYesACTIVE_PROCESSES or COMPLETED_PROCESSES
removeFailedquerybooleanOptionalExcludes failed/errored processes when true. Applies to COMPLETED_PROCESSES only
date-fromquerystring ($date)OptionalRange start (YYYY-MM-DD). Applies to COMPLETED_PROCESSES only
date-toquerystring ($date)OptionalRange end (YYYY-MM-DD). Applies to COMPLETED_PROCESSES only
pagequeryintegerOptionalZero-indexed page number. Applies to COMPLETED_PROCESSES only
pageSizequeryintegerOptionalResults per page. Applies to COMPLETED_PROCESSES only
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/deposit-workflow?category=COMPLETED_PROCESSES&removeFailed=true&date-from=2026-01-01&date-to=2026-07-14&page=0&pageSize=50 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
[
    {
        "class": "DepositWorkflow",
        "walletAddress": "0x649590c78f702ed0cdeab07daf722673d2510afe",
        "cryptoAssetCode": "USDT",
        "transferAmount": 20.0002,
        "feeAmount": 0.00001613542206867,
        "feeAssetCode": "ETH",
        "walletTransferId": "a31a5f77-1826-4e20-a416-ba282c4fd864",
        "tag": null,
        "processInstanceId": "96ece4ff-463e-11f1-af10-22add62dcf14",
        "state": "Update Transfer Status - Complete",
        "message": null,
        "startTime": "2026-05-02T15:50:05.922Z",
        "endTime": "2026-05-02T15:53:27.104Z",
        "suspended": false,
        "tokenPriceUsd": 0.9997792134,
        "errorMessage": null
    },
    {
        "class": "DepositWorkflow",
        "walletAddress": "0x649590c78f702ed0cdeab07daf722673d2510afe",
        "cryptoAssetCode": "ETH",
        "transferAmount": 0.000811907277365572,
        "feeAmount": null,
        "feeAssetCode": null,
        "walletTransferId": null,
        "tag": null,
        "processInstanceId": "b6a8edc5-44f0-11f1-bce8-7a2b3ca44423",
        "state": "Check Deposit Amount",
        "message": null,
        "startTime": "2026-05-01T00:00:07.255Z",
        "endTime": "2026-05-01T00:00:08.580Z",
        "suspended": false,
        "tokenPriceUsd": 2255.9838392777,
        "errorMessage": null
    }
]

state reflects the current step in the deposit pipeline; a state ending in Complete indicates the deposit has been credited. feeAmount, feeAssetCode, and walletTransferId populate once the deposit has been processed on-chain.

POST /hermes-ws-gateway/api/rest/transfer-workflow Auth Required Create Transfer

REST equivalent of the WS TRANSFER_WORKFLOW channel CREATE command. Initiates a transfer either between two connected exchanges/venues, or from an exchange out to an external blockchain wallet address.

Headers

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

Request Body

FieldTypeRequiredDescription
fromExchangestringYesSource venue code, e.g. OPENTRADE, OKEX
toExchangestringYesDestination venue code, or BLOCKCHAIN to send to an external wallet
walletToAddressstringOptionalRequired only when toExchange is BLOCKCHAIN
cryptoAssetCodestringYesAsset to transfer, e.g. USDT
transferAmountnumberYesAmount to transfer

Exchange to Exchange

Request Body
{
    "fromExchange": "OPENTRADE",
    "toExchange": "BITMART",
    "cryptoAssetCode": "USDT",
    "transferAmount": 4
}

Exchange to Blockchain Wallet (Withdrawal)

This is the same POST /hermes-ws-gateway/api/rest/transfer-workflow endpoint used above — a withdrawal is simply a transfer where toExchange is set to BLOCKCHAIN and walletToAddress is the external destination address.

Withdraw Request Body
{
    "fromExchange": "OKEX",
    "toExchange": "BLOCKCHAIN",
    "walletToAddress": "0x1c93969dce56d7eeeb00679dcfe89d7e0f719979",
    "cryptoAssetCode": "USDT",
    "transferAmount": 15
}
Critical! Withdrawals to blockchain wallet addresses cannot be reversed. Double-check walletToAddress and cryptoAssetCode before submitting.
Track a withdrawal Once submitted, poll Transfer Workflow with category=ACTIVE_PROCESSES (in flight) or category=COMPLETED_PROCESSES (finished) to follow the withdrawal's progress. The response's txId is populated once the withdrawal is broadcast on-chain.
GET /hermes-ws-gateway/api/rest/transfer-workflow Auth Required Transfer Workflow

REST equivalent of the WS TRANSFER_WORKFLOW channel GET. Tracks the lifecycle of transfers created via Create Transfer, whether between exchanges or out to a blockchain wallet.

Query Parameters

NameInTypeRequiredDescription
categoryquerystringYesACTIVE_PROCESSES or COMPLETED_PROCESSES
removeFailedquerybooleanOptionalExcludes failed/errored processes when true. Applies to COMPLETED_PROCESSES only
date-fromquerystring ($date)OptionalRange start (YYYY-MM-DD). Applies to COMPLETED_PROCESSES only
date-toquerystring ($date)OptionalRange end (YYYY-MM-DD). Applies to COMPLETED_PROCESSES only
pagequeryintegerOptionalZero-indexed page number. Applies to COMPLETED_PROCESSES only
pageSizequeryintegerOptionalResults per page. Applies to COMPLETED_PROCESSES only
transferSubTypequerystringOptionalALL, or a more specific subtype to narrow results. Applies to COMPLETED_PROCESSES only
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/transfer-workflow?category=COMPLETED_PROCESSES&removeFailed=true&date-from=2026-07-01&date-to=2026-07-14&page=0&pageSize=500&transferSubType=ALL HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
[
    {
        "class": "TransferWorkflow",
        "fromExchange": "OPENTRADE",
        "toExchange": "OKEX",
        "cryptoAssetCode": "USDT",
        "transferAmount": 5,
        "walletTransferId": "ffa280b4-3c95-4741-bb25-d154193b6510",
        "tag": null,
        "processInstanceId": "b0d4b1a1-78ec-11f1-86a3-b6505867aca1",
        "state": "Completed",
        "message": null,
        "startTime": "2026-07-06T03:42:19.954Z",
        "endTime": "2026-07-15T18:36:19.707Z",
        "suspended": false,
        "walletFromAddress": "0x375b9d792d38105bee4b87f72941a6af071d9218",
        "feeAmount": 0.00001031880686044,
        "feeAssetCode": "ETH",
        "txId": "0x205cce2e2077c709a2c9f2b8fffe8861b30c2421bce308bdc87e662d8f90edfb",
        "exchangeTxId": null,
        "exchangeTransferId": null,
        "errorMessage": null,
        "tasks": null
    },
    {
        "class": "TransferWorkflow",
        "fromExchange": "OKEX",
        "toExchange": "OPENTRADE",
        "cryptoAssetCode": "USDT",
        "transferAmount": 5,
        "walletTransferId": "916e31ee-700b-4e60-b6c2-9d14ad651fe9",
        "tag": null,
        "processInstanceId": "fe8858c3-78dd-11f1-86a3-b6505867aca1",
        "state": "Completed",
        "message": null,
        "startTime": "2026-07-06T01:57:07.865Z",
        "endTime": "2026-07-06T01:59:28.529Z",
        "suspended": false,
        "walletFromAddress": "OKEX",
        "feeAmount": 0.097,
        "feeAssetCode": "USDT",
        "txId": null,
        "exchangeTxId": "413425468",
        "exchangeTransferId": "413425468",
        "errorMessage": null,
        "tasks": null
    }
]

walletFromAddress holds the source wallet address for on-chain transfers, or the source exchange name for exchange-internal transfers. txId is populated only for blockchain transfers; exchangeTxId/exchangeTransferId only for exchange-to-exchange transfers.