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
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
  • GET /public/time
  • GET /public/candles
/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
/yield/ path (Yield contracts; needs the Trade permission)
  • GET /yield/product
  • POST /yield/subscriptions
  • GET /yield/contracts/open, GET /yield/contracts/closed
  • GET /yield/contracts/{contractId}
  • GET /yield/summary, GET /yield/contracts/{contractId}/performance
  • GET /yield/contracts/{contractId}/redemption-quote
  • POST /yield/contracts/{contractId}/redeem, POST /yield/contracts/{contractId}/cancel

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 your API key’s API 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

Before You Start: Create an API Key

Create a key under Account → API Keys: name it, choose its permissions and confirm with your second factor. The platform generates the key's API username, password and secret and shows them once, so store all three straight away.

CredentialExampleWhere it goes
API username100123_mybotThe username field in Step 1, and the {api-username} in the Step 2 URL — the same value both times
Password—The password field in Step 1
Secret—The clientSecret header in Step 2

The password expires one year after the key is created, and login is refused from then on — create a new key before that date.

Step 1: Login with the API Username and Password

Using POST method, send the API username and password 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
POST https://auth.opentrade.exchange/login

// Form Data (lowercase keys!)
username: {api-username}
password: {password}
Important! The username and password keys MUST be in lowercase. The login answers HTTP 302 whether or not it succeeded, so check where it redirects: a successful login redirects to the platform, a failed one back to /login. Only the SESSION cookie of a successful login can obtain a token in 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
POST https://auth.opentrade.exchange/auth/jwt/clients/{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.opentrade.exchange/login" \
    -d "username=[API_USERNAME]&password=[PASSWORD]" \
    -o /dev/null -w "login redirected to %{redirect_url}\n" \
    --next -s -b cookies.txt -X POST \
    "https://auth.opentrade.exchange/auth/jwt/clients/[API_USERNAME]/token" \
    -H "accept: */*" \
    -H "clientSecret: [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 (when the token expires) 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.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. 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.
eventTime The Open Trade gateway's clock, in Unix epoch milliseconds UTC, at the moment the snapshot was built. It is not the venue's matching-engine time. Every venue's book for one instrument carries the same value, and it advances on every request and every WebSocket push whether or not the book changed. For the current time on its own, call Server Time.
GET /hermes-ws-gateway/api/rest/public/time Auth Required Server Time

The Open Trade gateway's clock. Use it as "now" when deciding whether a candle has closed: a candle opened at T with length L has closed once serverTime >= T + L. Candles serves it about two minutes later, so a period that is still missing once serverTime >= T + L + 120000 had no trades.

Example Request
GET /hermes-ws-gateway/api/rest/public/time HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "serverTime": 1790593200123
}
serverTime Unix epoch milliseconds, UTC, read from the same gateway host clock that stamps eventTime on the order book.
GET /hermes-ws-gateway/api/rest/public/candles Auth Required Candles

Closed OHLCV candles for one pair, newest first. A backtest session serves the same path, parameters and rows for a venue's own trades; pass exchange explicitly so one call works on both.

Query Parameters

NameInTypeRequiredDescription
instrumentquerystringYesPair code, e.g. LTC/USDT
exchangequerystringOptionalDefault OPENTRADE: candles built from public trades on every connected venue, the series the Open Trade chart shows and the reference for SMART orders. Pass a venue code (HUOBI, OKEX, BITGET…) for that venue's own trades
periodquerystringOptionalOne of ONE_MIN (default), FIVE_MIN, FIFTEEN_MIN, ONE_HOUR, FOUR_HOURS, ONE_DAY
toqueryintegerOptionalEpoch milliseconds. Only candles that end at or before to, rounded down to the period, are returned. Default: now. To page back, pass the oldest openTime you already have
limitqueryintegerOptionalHow many periods to cover, 1 to 1000. Default 100
AuthorizationheaderstringYesBearer JWT token
Example Request
GET /hermes-ws-gateway/api/rest/public/candles?instrument=LTC/USDT&period=ONE_HOUR&limit=300 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
[
    [1790589600000, 84.1, 85.0, 83.9, 84.7, 1520.5],
    [1790586000000, 83.5, 84.2, 83.4, 84.1, 990.0]
]
Rows Each row is [openTime, open, high, low, close, volume]. openTime is the start of the period in epoch milliseconds UTC, and periods line up with UTC boundaries (hours on :00, four hours on 00, 04, 08, 12, 16 and 20 UTC). Prices come from executed public trades, not the book midpoint, and volume is in the base asset. A period with no trades has no row.
Only closed candles are returned The candle still forming is never served, so every row is final. A candle appears about two minutes after its period ends, once the last trades of that period have been collected: the 10:00–11:00 hour is served from about 11:02 UTC.
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
pricenumberYesThe limit price for LIMIT and POST_ONLY, and the trigger for BUY_STOP and SELL_STOP. For MARKET, STOP_LOSS and TAKE_PROFIT send the current price as a reference
slnumberOptionalStop loss trigger. Required for STOP_LOSS. On a LIMIT, MARKET, BUY_STOP or SELL_STOP entry it attaches a stop loss. On a TAKE_PROFIT it links a stop loss to it
tpnumberOptionalTake profit trigger. Required for TAKE_PROFIT. On a LIMIT, MARKET, BUY_STOP or SELL_STOP entry it attaches a take profit. On a STOP_LOSS it links a take profit to it
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"
    }
]

Take profit and stop loss

A LIMIT, MARKET, BUY_STOP or SELL_STOP entry may carry tp, sl or both. With both, the two exits are one-cancels-other. Leave exchange out: take profit and stop loss need smart routing. For a BUY set sl below and tp above the entry price, for a SELL the reverse; for a BUY_STOP or SELL_STOP the entry price is its stop price. The exits arm as the entry fills, sized to what you received. The rules are the same as on the WebSocket TRADE_PRIVATE channel.

To protect a position you already hold, send one STOP_LOSS or TAKE_PROFIT order carrying both sl and tp, with direction set to the side that closes the position and amount to the quantity to protect. The two exits are one-cancels-other and the quantity is reserved once for the pair. Leave exchange out. For a SELL set sl below and tp above the current price, for a BUY the reverse.

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/journal Auth Required Journal

One entry per action on your account — a fill, a transfer, a deposit, a withdrawal, a yield movement or a fee — assembled from the accounting ledger. Where /trade-private/trades-history reports what executed on an exchange, the journal reports what it did to your balances: the debits, the credits, the fees charged and the balances each action left behind.

One entry, many postings A single action can move several assets at once — a buy debits the quote currency, credits the base currency and charges a fee. Those are one journal entry with a debits, credits and fees list, not three unrelated rows. The postings array always carries the individual ledger rows behind the entry. Debits are negative and credits positive, so the postings of an entry sum to what it did to your balances.

Query Parameters

NameInTypeRequiredDescription
sizequeryintegerOptionalEntries per page. Default: 50, maximum 500. Anything outside 1..500 is rejected with 400
pagequeryintegerOptionalZero-based page number. Default: 0. A negative page is rejected with 400
periodTypequerystringOptionalDefault: L30D. See period values below
atdPeriodStartquerystring ($date-time)OptionalRange start (ISO-8601), required when periodType=ATD
atdPeriodEndquerystring ($date-time)OptionalRange end (ISO-8601), required when periodType=ATD
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0

The client is taken from the token, so there is no way to request another account’s journal.

Period Values

L24H, DTD (today), L7D, WTD, L30D, MTD, L6M, L12M, YTD, ATD (the window given by atdPeriodStart and atdPeriodEnd)

Statuses

COMPLETED, FAILED. A failed entry also carries statusDescription with the reason the ledger recorded.

Fee Types

EXCHANGE, BROKER, CLIENT, SWAP, NETWORK

Action Types

BUY, SELL, DEPOSIT, WITHDRAWAL, TRANSFER, YIELD_SUBSCRIPTION, YIELD_HARVEST, YIELD_REDEMPTION, YIELD_MOVEMENT, DAILY_SETTLEMENT, TRADING_FEE, EXCHANGE_FEE, BROKER_FEE, NETWORK_FEE, FINANCING_FEE, ADJUSTMENT

200 Response
{
    "content": [
        {
            "actionKey": "11788521799959",
            "actionType": "BUY",
            "actionName": "Bought",
            "clientId": 1000123,
            "time": "2026-08-31T14:02:11",
            "startTime": "2026-08-31T14:02:09",
            "baseAsset": "BTC",
            "quoteAsset": "USDT",
            "quantity": 0.25,
            "price": 88012.4,
            "route": ["OKEX"],
            "debits": [{"asset": "USDT", "amount": -22003.1}],
            "credits": [{"asset": "BTC", "amount": 0.25}],
            "fees": [{"asset": "USDT", "amount": 11.0, "feeType": "EXCHANGE"}],
            "balances": [{"asset": "BTC", "amount": 1.35}],
            "status": "COMPLETED",
            "statusDescription": null,
            "clientOrderId": "a7c1f0e2-5d44-4e21-9f0b-6e2b8f0d1c33",
            "transactionGroupId": "4a248fbd-1cd8-3164-b081-26f40e8248ac",
            "postings": [
                {
                    "id": 11788521799959,
                    "clientId": 1000123,
                    "assetType": "BTC",
                    "amount": 0.25,
                    "price": 88012.4,
                    "priceCurrency": "USDT",
                    "time": "2026-08-31T14:02:11",
                    "description": "Buy BTC/USDT",
                    "transactionType": "BUY",
                    "operation": "EXECUTE_WITH_UNLOCK",
                    "origin": "TOMS",
                    "status": "SUCCESS",
                    "assetTypeBalance": 1.35,
                    "priceCurrBalance": 150244.02,
                    "transactionGroupId": "4a248fbd-1cd8-3164-b081-26f40e8248ac",
                    "exchange": "OKEX",
                    "clientOrderId": "a7c1f0e2-5d44-4e21-9f0b-6e2b8f0d1c33"
                }
            ]
        }
    ],
    "number": 0,
    "size": 50,
    "totalElements": 120
}
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,
        "avgPriceUsd": 90550.7416782,
        "index": 88010.42919245128,
        "onOrders": 0.0,
        "available": 0.0019553,
        "marketValue": 172.0867922,
        "unrealizedPnl": -4.967073,
        "notional": 177.0538652
    }
]

avgPriceUsd is the average price paid for the quantity still open, which is your cost basis over that quantity; index is the current mark price used for valuation. notional is that cost basis in USD, so marketValue less notional is unrealizedPnl, which 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,
        "marketValueUsd": 30803.6502,
        "avgPriceUsd": 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,
        "marketValueUsd": 10561.2515,
        "avgPriceUsd": 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.
avgPriceUsdnumberAverage price paid for the quantity still open on that venue, in USD. Equal to costBasisUsd divided by finalBalance.
costBasisUsdnumberUSD paid for the quantity still open on that venue. Anything already closed is excluded.
marketValueUsdnumberCurrent USD market value of the holding on that venue.
unrealizedPnlnumberUnrealized PnL on the holding, in USD, measured as market value less cost basis. Negative when the position is under water, and zero when nothing was paid for the holding.
returnPercentnumberReturn on the holding, in percent, measured against the cost basis. Zero when nothing was paid for the holding.

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/wallets 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/processes/active Auth Required Deposit Workflow: Active
GET /hermes-ws-gateway/api/rest/deposit/processes/completed Auth Required Deposit Workflow: Completed

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. /active returns the deposits still in progress as a plain list and takes no parameters; /completed returns the finished ones a page at a time.

Query Parameters

NameInTypeRequiredDescription
removeFailedquerybooleanOptionalExcludes failed/errored processes when true. Default false. Completed only
dateFromquerystring ($date)OptionalRange start (YYYY-MM-DD). Completed only
dateToquerystring ($date)OptionalRange end (YYYY-MM-DD). Completed only
pagequeryintegerOptionalZero-indexed page number. Default 0. Completed only
pageSizequeryintegerOptionalResults per page, 1 to 200. Default 50. Completed only
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/deposit/processes/completed?removeFailed=true&dateFrom=2026-01-01&dateTo=2026-07-14&page=0&pageSize=50 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response items (/active body; items of a /completed page)
[
    {
        "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
    },
    {
        "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
    }
]

/completed returns a page: { "items": [...], "page": 0, "pageSize": 50, "totalItems": 2, "totalPages": 1 }. Its items carry the fields shown above; /active items also carry the processing detail of a deposit still in flight: hotWalletAddress, retryCount, maxRetries, batchId, batchTransactionId, batchStatus and tasks.

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.

GET /hermes-ws-gateway/api/rest/transfer/fee-quote Auth Required Transfer Fee Quote

REST equivalent of the WS TRANSFER_FEE_QUOTE channel GET. Prices a transfer or withdrawal before it is created: the venue and network fees it will be charged, and what will reach the destination. Show it to the client, then pass its feeAmount as confirmedFee on Create Transfer.

Query Parameters

NameInTypeRequiredDescription
cryptoAssetCodequerystringYesAsset to transfer, e.g. USDT
amountquerynumberYesWhole amount to be debited. Must be greater than zero; a missing asset, venue or amount is rejected with 400
fromExchangequerystringYesSource venue code, e.g. OKEX or OPENTRADE
toExchangequerystringYesDestination venue code, or BLOCKCHAIN for a withdrawal
walletToAddressquerystringOptionalDestination address of a withdrawal
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/transfer/fee-quote?cryptoAssetCode=USDT&amount=15&fromExchange=OKEX&toExchange=BLOCKCHAIN&walletToAddress=0x1c93969dce56d7eeeb00679dcfe89d7e0f719979 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "class": "TransferFeeQuote",
    "cryptoAssetCode": "USDT",
    "amount": 15,
    "fromExchange": "OKEX",
    "toExchange": "BLOCKCHAIN",
    "quoted": true,
    "sendable": true,
    "feeAssetCode": "USDT",
    "feeAmount": 1.35,
    "venueFee": 1,
    "networkFee": 0.35,
    "receiveAmount": 13.65,
    "minimumAmount": 2,
    "refusal": null,
    "reason": null
}

Quote Fields

FieldTypeDescription
quotedbooleanfalse when the venue or network could not price the fee right now; reason says why
sendablebooleanfalse when the transfer would be refused, for example because the amount does not cover the fee and the venue's minimum; refusal says why
feeAssetCodestringAsset the fee is charged in — the transferred asset
feeAmountnumberTotal fee, venueFee plus networkFee. Send it back as confirmedFee when you create the transfer
venueFeenumberWithdrawal fee of the source venue, null when the transfer does not leave a venue
networkFeenumberNetwork fee of the on-chain send from the platform wallet, null when there is none
receiveAmountnumberWhat reaches the destination: amount less feeAmount, rounded down to what the venue can send
minimumAmountnumberSmallest amount the source venue will send
refusalstringWhy the transfer is not sendable, null when it is
reasonstringWhy the fee could not be quoted, null when it was
POST /hermes-ws-gateway/api/rest/transfer/start 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
transferAmountnumberYesWhole amount to debit; the fees come out of it
confirmedFeenumberOptionalThe feeAmount of the fee quote the client confirmed. The transfer is never charged more, and is refused with 409 if the fee has risen
Fees come out of the amount transferAmount is the whole amount debited from your balance. The venue's withdrawal fee and the network fee are taken out of it and the destination receives the rest. Quote it first with Transfer Fee Quote and pass its feeAmount as confirmedFee: the transfer is then never charged more than the client confirmed, and is refused rather than sent if the fee has risen. Without confirmedFee the fee is priced again as the funds are sent and charged at that price, which may be higher than the quote, and when no fee can be quoted it is sent in full and the venue may charge its fees afterwards.

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/start 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,
    "confirmedFee": 1.35
}
Critical! Withdrawals to blockchain wallet addresses cannot be reversed. Double-check walletToAddress and cryptoAssetCode before submitting.
Track a withdrawal Once submitted, poll Transfer Workflow at /transfer/processes/active (in flight) or /transfer/processes/completed (finished) to follow the withdrawal's progress. The response's txId is populated once the withdrawal is broadcast on-chain.

Fee Refusals (409 Conflict)

CodeDescription
FEE_CHANGEDThe fee has risen above confirmedFee. Quote again and ask the client to confirm the new fee
FEE_UNAVAILABLEconfirmedFee was sent but the fee cannot be quoted right now. Retry later
FEE_REFUSEDThe amount does not cover the fee and the venue's minimum

A refused transfer starts nothing and locks nothing. Each fee is priced again just before its leg is sent. If the venue's fee has risen above the one quoted at start (above confirmedFee itself when the quote has no networkFee), or the network fee above what confirmedFee leaves for it before anything has left the venue, the transfer ends without sending, your balance is released, and it appears among the completed transfers with its errorMessage. Once the funds have left the venue, a network fee over that is charged at the limit and the platform bears the rest.

409 Response
{
    "class": "TransferWorkflow",
    "state": "FEE_CHANGED",
    "message": "The fee on this transfer is now 1.6 USDT, above the 1.35 USDT confirmed"
}
GET /hermes-ws-gateway/api/rest/transfer/processes/active Auth Required Transfer Workflow: Active
GET /hermes-ws-gateway/api/rest/transfer/processes/completed Auth Required Transfer Workflow: Completed

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. /active returns the transfers still in progress as a plain list and takes no parameters; /completed returns the finished ones a page at a time.

Query Parameters

NameInTypeRequiredDescription
removeFailedquerybooleanOptionalExcludes failed/errored processes when true. Default false. Completed only
dateFromquerystring ($date)OptionalRange start (YYYY-MM-DD). Completed only
dateToquerystring ($date)OptionalRange end (YYYY-MM-DD). Completed only
pagequeryintegerOptionalZero-indexed page number. Default 0. Completed only
pageSizequeryintegerOptionalResults per page, 1 to 200. Default 50. Completed only
transferSubTypequerystringOptionalALL (default), TRANSFER_ONLY for transfers between venues, or WITHDRAWAL_ONLY for withdrawals to a blockchain address. Completed only
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/transfer/processes/completed?removeFailed=true&dateFrom=2026-07-01&dateTo=2026-07-14&page=0&pageSize=50&transferSubType=ALL HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response items (/active body; items of a /completed page)
[
    {
        "fromExchange": "OPENTRADE",
        "toExchange": "OKEX",
        "cryptoAssetCode": "USDT",
        "transferAmount": 5,
        "confirmedFee": null,
        "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
    },
    {
        "fromExchange": "OKEX",
        "toExchange": "OPENTRADE",
        "cryptoAssetCode": "USDT",
        "transferAmount": 5,
        "confirmedFee": null,
        "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
    }
]

/active returns these objects as a plain list; /completed returns the same objects in a page: { "items": [...], "page": 0, "pageSize": 50, "totalItems": 2, "totalPages": 1 }.

confirmedFee is always null on these two endpoints; the fee a client confirmed is not read back here. 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.

Yield

Yield earns the funding rate on a perpetual swap while holding the matching spot position, so the contract carries no net price exposure. You subscribe an amount of the quote asset, the platform buys the base asset spot and shorts the same quantity on the perpetual, and the funding it collects is credited to you daily, less the performance fee. A contract runs until you redeem it.

Permission Every Yield endpoint needs the Trade permission on the API key, the same one that places orders. A key made on a sub-account reads and acts on that sub-account's contracts.
Follow a contract as it works Subscribing, redeeming and cancelling each return as soon as the request is accepted; the contract then works through its stages over the next minutes. Subscribe to the YIELD_CONTRACT WebSocket channel to have each change pushed to you, or poll Get Contract and watch status and step.
GET /hermes-ws-gateway/api/rest/yield/product Auth Required Yield Product

The terms a subscription must meet, and how much you can subscribe from each funding venue right now.

Parameters

NameInTypeRequiredDescription
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/yield/product HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "enabled": true,
    "quoteAsset": "USDT",
    "baseAssets": ["DOGE"],
    "minAmount": 50,
    "maxAmount": 100000,
    "performanceFeePercent": 15,
    "venue": "HTX",
    "headlineApyPercent": 10.5,
    "fundingVenues": [
        {
            "exchange": "HUOBI",
            "freeBalance": 1250.4,
            "maxSubscribable": 1250.4
        }
    ]
}

Product Fields

FieldTypeDescription
enabledbooleanfalse while Yield is closed to new subscriptions; open contracts keep running
quoteAssetstringAsset you subscribe and are paid in
baseAssetsarrayAssets a contract can be built on
minAmount / maxAmountnumberLimits on one subscription, in quoteAsset
performanceFeePercentnumberShare of the gross funding income kept as the performance fee
venuestringWhere the strategy runs
headlineApyPercentnumberIndicative annual rate, when one is published; not a promise
fundingVenuesarrayPer venue you can fund from: its freeBalance in quoteAsset and the maxSubscribable amount after the limits
POST /hermes-ws-gateway/api/rest/yield/subscriptions Auth Required Subscribe

Starts a contract with the amount you name, taken from one funding venue. Send a clientRequestId of your own on every subscription: a repeat of the same request, after a timeout say, returns the contract the first one started instead of starting a second.

Request Body

FieldTypeRequiredDescription
baseAssetstringYesOne of the product's baseAssets, e.g. DOGE
amountnumberYesPrincipal in quoteAsset, between minAmount and maxAmount
sourceExchangestringOptionalFunding venue, one of fundingVenues. Defaults to the product's funding venue
clientRequestIdstringOptionalYour idempotency key, up to 64 characters
Example Request
POST /hermes-ws-gateway/api/rest/yield/subscriptions HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json

{
    "baseAsset": "DOGE",
    "amount": 1000,
    "sourceExchange": "HUOBI",
    "clientRequestId": "bot-2026-09-22-001"
}
202 Response
{
    "contractId": "7c1d5e2a-5b8e-11f1-9a51-0242ac120004",
    "created": true
}

202 means a new contract was started. 200 with "created": false means this clientRequestId had already started the contract named. A refused subscription starts nothing and moves nothing, and answers with the status below and a body of refusal and message:

409 Response
{
    "created": false,
    "refusal": "INSUFFICIENT_FUNDS",
    "message": "Only 420 USDT is free on HUOBI"
}

Refusal Codes

refusalHTTPMeaning
PRODUCT_DISABLED409Yield is not open for subscriptions
INVALID_REQUEST400A required field is missing or malformed, e.g. no asset, a non-positive amount or a clientRequestId over 64 characters
ASSET_NOT_OFFERED409The asset is not in baseAssets
VENUE_NOT_OFFERED409sourceExchange is not one of fundingVenues
BELOW_MINIMUM / ABOVE_MAXIMUM409The amount is outside minAmount–maxAmount
INSUFFICIENT_FUNDS409The funding venue's free balance does not cover the amount
CONTRACT_NOT_FOUND404No contract of yours has that id
NOT_REDEEMABLE409The contract cannot be redeemed now; message names its stage
NOT_CANCELLABLE409The contract is past subscribing and can only be redeemed
GET /hermes-ws-gateway/api/rest/yield/contracts/open Auth Required Open Contracts
GET /hermes-ws-gateway/api/rest/yield/contracts/closed Auth Required Closed Contracts

/open returns every contract that has not settled, as a plain list. /closed returns the settled ones — redeemed, matured, cancelled or failed — a page at a time, newest first.

Parameters

NameInTypeRequiredDescription
dateFromquerystringOptionalClosed only. ISO date; contracts started on or after it
dateToquerystringOptionalClosed only. ISO date; contracts started on or before it
pagequeryintegerOptionalClosed only. Zero-based page, default 0
pageSizequeryintegerOptionalClosed only. Default 50, at most 200; outside that is rejected with 400
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/yield/contracts/closed?page=0&pageSize=50 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Each entry is a contract as Get Contract returns it; /closed wraps them as { "items": [...], "page": 0, "pageSize": 50, "totalItems": 3, "totalPages": 1 }.

GET /hermes-ws-gateway/api/rest/yield/contracts/{contractId} Auth Required Get Contract

One contract, with its legs, its income so far, the income accrued since the last credit, and each credit. Answers 404 for an id that is not one of your contracts.

Parameters

NameInTypeRequiredDescription
contractIdpathstringYesThe contract's contractId
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/yield/contracts/7c1d5e2a-5b8e-11f1-9a51-0242ac120004 HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "contractId": "7c1d5e2a-5b8e-11f1-9a51-0242ac120004",
    "clientId": 24240001,
    "clientRequestId": "bot-2026-09-22-001",
    "baseAsset": "DOGE",
    "quoteAsset": "USDT",
    "contractCode": "DOGE-USD",
    "status": "ACTIVE",
    "statusLabel": "Active",
    "step": "Active — earning",
    "redeemable": true,
    "cancellable": false,
    "redemptionRequested": false,
    "fundingVenue": "HUOBI",
    "venue": "HUOBI",
    "redemptionWithdrawsFromVenue": false,
    "principal": 1000,
    "performanceFeePercent": 15,
    "openedAt": "2026-09-01T09:14:05",
    "spotFilledQty": 4012,
    "spotAvgPrice": 0.2489,
    "perpContracts": 4012,
    "perpAvgPrice": 0.2491,
    "cumulativeYieldGross": 9.41,
    "cumulativeFees": 1.41,
    "cumulativeYieldNet": 8,
    "pendingYieldBase": 2.5,
    "pendingYieldQuote": 0.62,
    "pendingYieldNet": 0.527,
    "lastHarvestAt": "2026-09-22T00:10:00",
    "credits": [
        {
            "creditedAt": "2026-09-22T00:10:00",
            "grossAmount": 0.47,
            "feeAmount": 0.07,
            "netAmount": 0.4,
            "baseAssetAmount": 1.89
        }
    ]
}

Contract Fields

FieldTypeDescription
contractIdstringIdentifier of the contract; use it on every per-contract endpoint
clientRequestIdstringThe idempotency key the subscription was made with, null when none was sent
statusstringSUBSCRIBING, ACTIVE, HARVESTING, REDEEMING, PENDING_UNWIND, CLOSED, CANCELLED or FAILED
contractCodestringThe perpetual the hedge is held in, e.g. DOGE-USD; its second part is the currency perpAvgPrice is quoted in
statusLabelstringThe status in client wording, as the web app shows it
stepstringWhat the contract is doing right now, in client wording; null once it has settled
redeemablebooleantrue while the contract is earning and no redemption has been asked for
cancellablebooleantrue while the contract is still being built and no cancellation has been asked for
redemptionRequestedbooleanA redemption or cancellation has been asked for and is being worked
fundingVenuestringVenue the principal was taken from
venuestringVenue the strategy runs on
redemptionWithdrawsFromVenuebooleantrue when a redemption comes back through a venue withdrawal, which carries that venue's fee
principalnumberAmount subscribed, in quoteAsset
performanceFeePercentnumberShare of the gross funding income kept as the performance fee
openedAt / closedAt / cancelledAtstringWhen the contract started earning, settled, or was cancelled (UTC)
subscriptionTransferFeenumberFee taken from the principal to move it to the venue, when it had to move
spotFilledQty / spotAvgPricenumberThe long spot leg: quantity bought and its average price
perpContracts / perpAvgPricenumberThe short perpetual leg: size and its average price
cumulativeYieldGross / cumulativeFees / cumulativeYieldNetnumberFunding income credited so far, the performance fee on it, and what reached you, in quoteAsset
pendingYieldBase / pendingYieldQuotenumberIncome accrued since the last credit and not yet sold, in the base asset and its current quoteAsset value
pendingYieldNetnumberpendingYieldQuote less the performance fee: what the pending income would add to your balance
lastHarvestAtstringWhen income was last credited
creditsarrayOne entry per credit: creditedAt, grossAmount, feeAmount, netAmount, baseAssetAmount
redemptionAmount / redemptionTransferFeenumberWhat a settled contract returned to you and the venue withdrawal fee taken from it
redemptionReasonstringCLOSE, CANCEL or MATURITY once a redemption has started
txIdstringOn-chain transaction of the principal's move to the venue, when it had to move
GET /hermes-ws-gateway/api/rest/yield/summary Auth Required Account Summary
GET /hermes-ws-gateway/api/rest/yield/contracts/{contractId}/performance Auth Required Contract Performance

/summary totals every contract you have held; /contracts/{contractId}/performance gives the same figures for one contract. Both are what the web app's Yield page shows.

Parameters

NameInTypeRequiredDescription
contractIdpathstringYesContract performance only
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/yield/summary HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "openPrincipal": 1000,
    "currentValue": 1008.527,
    "lifetimeIncome": 8,
    "lifetimeFees": 1.41,
    "openContracts": 1,
    "deployedContracts": 1,
    "apyPercent": 13.9,
    "pendingByAsset": { "DOGE": 2.5 },
    "pendingValue": 0.527,
    "pendingUnreadable": false,
    "estimatedDays": false,
    "nav": [
        { "date": "2026-09-21", "value": 1007.6, "income": 0.41 },
        { "date": "2026-09-22", "value": 1008.53, "income": 0.4 }
    ]
}

Performance Fields

FieldTypeDescription
openPrincipalnumberPrincipal of the contracts still open
currentValuenumberopenPrincipal plus the income they have earned, credited and pending, net of the performance fee
lifetimeIncome / lifetimeFeesnumberNet income credited and performance fees charged, over every contract
openContracts / deployedContractsintegerContracts still open, and contracts that ever put principal to work
apyPercentnumberAnnualised return on the principal-days deployed; null until a week of history exists
pendingByAsset / pendingValueobject / numberIncome accrued since the last credit: gross per base asset, and in quoteAsset net of the performance fee
pendingUnreadablebooleantrue when pending income could not be read just now; it is then left out of the figures
estimatedDaysbooleantrue when some income could not be placed on the day it was earned and is spread evenly over the contract's life, so the daily figures in nav are partly estimated
navarrayDaily series over up to two years: the date, the position value at the end of it, and the income earned that day
GET /hermes-ws-gateway/api/rest/yield/contracts/{contractId}/redemption-quote Auth Required Redemption Fee Quote

The fee a redemption would take from what it returns. When redemptionWithdrawsFromVenue is false the funds come back without a withdrawal and feeAmount is 0; otherwise it is the venue's current withdrawal fee, in the same shape as Transfer Fee Quote. The fee is charged at the price in force when the funds leave the venue, which may differ from this quote.

Parameters

NameInTypeRequiredDescription
contractIdpathstringYesThe contract's contractId
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
GET /hermes-ws-gateway/api/rest/yield/contracts/7c1d5e2a-5b8e-11f1-9a51-0242ac120004/redemption-quote HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
200 Response
{
    "cryptoAssetCode": "USDT",
    "amount": 1000,
    "fromExchange": "HUOBI",
    "toExchange": "OPENTRADE",
    "quoted": true,
    "sendable": true,
    "feeAssetCode": "USDT",
    "feeAmount": 0
}
POST /hermes-ws-gateway/api/rest/yield/contracts/{contractId}/redeem Auth Required Redeem
POST /hermes-ws-gateway/api/rest/yield/contracts/{contractId}/cancel Auth Required Cancel

/redeem closes an earning contract: both legs are unwound at market and the principal plus any income not yet credited comes back to your balance, less the fee in Redemption Fee Quote. /cancel stops a contract that is still being built and returns what had been deployed. Check redeemable or cancellable on the contract first. Neither can be undone.

Parameters

NameInTypeRequiredDescription
contractIdpathstringYesThe contract's contractId
AuthorizationheaderstringYesBearer JWT token
X-API-VersionheaderstringOptionalDefault: 1.0.0
Example Request
POST /hermes-ws-gateway/api/rest/yield/contracts/7c1d5e2a-5b8e-11f1-9a51-0242ac120004/redeem HTTP/1.1
X-API-Version: 1.0.0
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
202 Response
{
    "contractId": "7c1d5e2a-5b8e-11f1-9a51-0242ac120004",
    "contract": { "status": "ACTIVE", "redemptionRequested": true, ... }
}

202 means the request was accepted; contract is the contract as it now stands. A contract that cannot be redeemed or cancelled now answers 409 with NOT_REDEEMABLE or NOT_CANCELLABLE, and an id that is not yours answers 404 with CONTRACT_NOT_FOUND — see Refusal Codes.

409 Response
{
    "contractId": "7c1d5e2a-5b8e-11f1-9a51-0242ac120004",
    "refusal": "NOT_REDEEMABLE",
    "message": "The contract is subscribing and cannot be redeemed now"
}