Public API

Introduction

Open Trade provides Quotes and Limit Order book for SPOT Crypto. This document describes Open Trade WebSocket communication with Open Trade trading services.

Open Trade Taker WEBSOCKET API provides the ability to connect to the venue server, subscribe to market data, place and control orders, receive executions and updates. The API is based on WEBSOCKET specification.

Key Features Real-time market data streams, unified order management across exchanges, portfolio tracking, and instant execution notifications.

WebSocket Server URL

PROD: wss://wss.opentrade.exchange/ws

Available Channels

Public Channels
  • ASSET_LIST
  • INSTRUMENT_LIST
  • ORDER_BOOK_PUBLIC
  • TRADE_PUBLIC
  • ACTIVE_SUBSCRIPTIONS
Private Channels
  • BALANCE
  • TRADE_PRIVATE
See the Private API documentation for details on these channels.

Precision & Symbols

Price Precision

The precision level of all trading prices is based on significant figures. All pairs on Bitfinex use up to 7 significant digits and up to 8 decimals (e.g., 1.234567, 123.4567, 1234.567, 0.0001234567). Prices submitted with a precision larger than 7 will be cut by the API.

Amount Precision

The amount field allows up to 8 decimals. Anything exceeding this will be rounded to the 8th decimal.

Symbols

A symbol identifies a trading pair (e.g., BTC/USD).

Connection

Establishing Connection

Connect to the WebSocket endpoint using any standard WebSocket client. Upon connection, you'll receive a confirmation message.

JavaScript Example
const ws = new WebSocket('wss://wss.opentrade.exchange/ws');

ws.onopen = () => {
    console.log('Connected to Open Trade');

    // Send ping every 30 seconds to keep connection alive
    setInterval(() => {
        ws.send(JSON.stringify({
            command: "PING",
            channel: "PING"
        }));
    }, 30000);
};

ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
};

ws.onerror = (error) => {
    console.error('WebSocket error:', error);
};

ws.onclose = () => {
    console.log('Connection closed');
};

Subscription

Subscription is required to establish a data channel the server will push updates to. If private channels are required, the valid API key must be provided in every Subscribe request.

Subscription Structure
{
    "requestId": "123",
    "command": "SUBSCRIBE",
    "signature": "put your token here for private channels",
    "channel": "CHANNEL_NAME",
    "channelArgs": [
        {
            "name": "parameter_name",
            "value": "parameter_value"
        }
    ]
}

Example: Subscribe to Balance (Private Channel)

Request
{
    "command": "SUBSCRIBE",
    "signature": "{{BEARER_TOKEN}}",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC, USDT]"
        }
    ],
    "channel": "BALANCE"
}
Response
{
    "command": "SUBSCRIBE",
    "event": "SNAPSHOT",
    "channel": "BALANCE",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC, USDT]"
        }
    ],
    "data": [
        {
            "class": "Balance",
            "currencyCode": "USDT",
            "balance": 313037.3739066097,
            "available": 313037.3739066097,
            "locked": 0.0
        },
        {
            "class": "Balance",
            "currencyCode": "BTC",
            "balance": 3.28944117,
            "available": 2.7886285699999998,
            "locked": 0.5008126
        }
    ]
}

Rate Limits

Connection Rate Limit The rate limit for wss://wss.opentrade.exchange/ws is set at 5 connections per 15 seconds.

To ensure fair usage and system stability, rate limits are enforced on WebSocket connections. Exceeding these limits may result in temporary connection rejection.

Heartbeat / Ping

Critical! Failure to send a heartbeat within two minutes will lead to connection closure by the server!

Ping is a service that users need to upkeep to notify that WebSocket connection is still open.

PING Keep Alive

Maintains the WebSocket connection active. Must be sent at least once every 2 minutes.

Request
{
    "command": "PING",
    "channel": "PING"
}
Response
{
    "event": "PONG",
    "channel": "PING"
}

Public Channels

Public channels provide market data and instrument information. All API access — including public channels — requires authentication with your API key. Complete the authentication flow below before subscribing to any channel.

GET Asset List

Provides a list of supported assets and their trading specifications.

Request
{
    "command": "GET",
    "channel": "ASSET_LIST"
}
Response
{
    "event": "GET",
    "channel": "ASSET_LIST",
    "data": [
        {
            "class": "Currency",
            "code": "USC",
            "name": null
        },
        ...
    ]
}
GET Instrument List

Provides a list of supported Instruments and their trading specifications. When no symbol is provided, all Instruments are returned, a specific Instrument is provided only selected is returned.

Request
{
    "command": "GET",
    "channel": "INSTRUMENT_LIST"
}
Response
{
    "event": "GET",
    "channel": "INSTRUMENT_LIST",
    "data": [
        {
            "class": "Instrument",
            "quoteCurrencyCode": "BAT",
            "code": "BAT/ETH",
            "name": null
        },
        ...
    ]
}
Order Book (Price Book)

Provides streaming services an order book for selected symbol, user needs to provide levels of order book to receive. MAX is 20. MIN is 1. Order books are sorted based on NBBO price: BIDs best (Max) first then descending, ASKs best (MIN) first then ascending. The whole Order book is updated every 20MS regardless of changes.

Subscribe Request
{
    "command": "SUBSCRIBE",
    "channel": "ORDER_BOOK_PUBLIC",
    "channelArgs": [
        {
            "name": "instrument",
            "value": "[USD/ADA,ETH/BTC]"
        }
    ]
}
Acknowledgment
{
    "command": "SUBSCRIBE",
    "event": "ACK",
    "channel": "ORDER_BOOK_PUBLIC"
}
Data Update
{
    "command": "SUBSCRIBE",
    "event": "UPDATE",
    "channel": "ORDER_BOOK_PUBLIC",
    "data": [
        {
            "class": "OrderBook",
            "exchange": "CROSSTOWER",
            "symbol": "BTC/USD",
            "bids": [
                [19292.21, 0.0124],
                [19242.45, 3.0516],
                [10000.0, 0.0002]
            ],
            "asks": [
                [85100.0, 0.01009],
                [19397.85, 21.6067],
                [84300.0, 0.00854]
            ],
            "eventTime": 1664651366635
        },
        ...
    ]
}
Trade Book

Provides streaming services a trading book (public trades) for selected symbol. Once subscribed updates will be pushed to user as they appear at Open Trade.

Subscribe Request
{
    "command": "SUBSCRIBE",
    "channel": "TRADE_PUBLIC",
    "channelArgs": [
        {
            "name": "instrument",
            "value": "[USD/ADA,ETH/BTC]"
        }
    ]
}
Acknowledgment
{
    "command": "SUBSCRIBE",
    "event": "ACK",
    "channel": "TRADE_PUBLIC"
}
Data Update
{
    "command": "SUBSCRIBE",
    "event": "UPDATE",
    "channel": "TRADE_PUBLIC",
    "data": [
        {
            "class": "PublicTrade",
            "exchange": "OKCOIN",
            "symbol": "BTC/USD",
            "price": 19308.6,
            "quantity": 0.0103,
            "tradeSide": "BUY",
            "eventTime": 1664651920827
        },
        ...
    ]
}

Authentication

All API access requires authentication with an API key. Obtain a JWT token through a two-step process and include it as the signature parameter in every request.

Authentication Steps
  1. POST your API key credentials to the login endpoint to obtain a SESSION cookie
  2. POST to the JWT endpoint with the cookie and your client secret to obtain a JWT
  3. Include the JWT as the signature field in every channel request

Authentication Flow

Step 1: Login with API Key

Send a POST request to the login endpoint with your API key as the username and your API secret as the password. Credentials must be sent as form-data with lowercase keys.

Login Endpoints
POST https://auth.opentrade.exchange/login

// Form Data (lowercase keys!)
username: {your_api_key_username}
password: {your_api_secret}
Important! The form keys username and password MUST be lowercase. After successful login, the response sets a SESSION cookie that you'll use in Step 2.

Step 2: Obtain JWT Token

Send a POST request to the token endpoint. Pass the SESSION cookie from Step 1 and your client secret in the clientSecret request header. The body must be empty.

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

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

// Body
(empty - send Content-Length: 0)
Notes on the JWT response
  • Response Content-Type is text/plain — body is the raw token string prefixed with Bearer
  • Token lifetime is returned in the jwt-expire-at response header (currently 1 hour)
  • Token scope is returned in the jwt-scope response header (e.g., api.access)
  • To refresh, repeat the full two-step flow before expiry

Complete Authentication Flow with cURL

cURL Example
curl -s --cookie-jar cookies.txt -X POST \
    "https://auth.opentrade.exchange/login" \
    -d "username=[API_USER_NAME]&password=[API_SECRET]" \
    --next -s -b cookies.txt -X POST \
    "https://auth.opentrade.exchange/auth/jwt/clients/[API_USER_NAME]/token" \
    -H "accept: */*" \
    -H "clientSecret: [API_SECRET]" \
    -d ""

Python Example

Python (requests)
import requests

BASE = "https://auth.opentrade.exchange"
USERNAME = "your_api_key_username"
SECRET = "your_api_secret"

session = requests.Session()

# Step 1: Login -> SESSION cookie
session.post(
    f"{BASE}/login",
    data={"username": USERNAME, "password": SECRET},
    allow_redirects=False,
)

# Step 2: Exchange SESSION cookie for JWT
resp = session.post(
    f"{BASE}/auth/jwt/clients/{USERNAME}/token",
    headers={"clientSecret": SECRET},
)
jwt = resp.text  # 'Bearer eyJ...'
print(jwt)
Success! The response body contains your JWT (prefixed with Bearer ). Use the full string — including the Bearer prefix — as the signature parameter in all channel requests.
Common errors
  • HTTP 400 on token request — missing clientSecret header, missing cookie, or wrong HTTP method (must be POST, not GET)
  • HTTP 404 on token request — path uses /clients/ (plural), not /client/
  • Login returns no SESSION cookie — verify form keys are lowercase and sent as application/x-www-form-urlencoded

Using Your Token

Include the JWT in every channel request as the signature field — this applies to both public and private channels.

Example with Token
{
    "command": "SUBSCRIBE",
    "signature": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "channel": "BALANCE",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC,USD]"
        }
    ]
}
Token Management Tips
  • Store API keys and tokens securely — never expose them in client-side code
  • Tokens expire after 1 hour — check the jwt-expire-at response header from Step 2
  • Implement refresh logic that re-runs the full two-step flow before expiry to maintain continuous connectivity
  • Use environment variables or a secret manager to handle credentials across environments
  • Pass the token verbatim, including the Bearer prefix returned by the auth server
Next Steps For information on Private Channels, Order Management, and Trading operations, please see the Private API documentation (Part 2).