NAV

OVERVIEW

Introduction

Welcome to HashKey Singapore Site API Documentation!

Rest API

Our REST API offers a simple and secure way to manage orders and monitor your digital asset portfolios. The REST API can be publicly access endpoints via market data endpoints and private authenticated endpoints for trading, funding and account data which require requests to be signed.

Websocket API

Use an asynchronous method (pub/sub) approach to efficiently deliver push notifications for orders, transactions, market and other pertinent information. By subscribing to specific topics of interest, users can receive real-time updates without the need for constant polling.

Test our sandbox

Please direct any questions or feedback to [[email protected]] to obtain sandbox account.

📘 All 2FA/SMS/Email verification code is defaulted to "123456" in Sandbox environment for ease of use

1. Go to our sandbox website page:

📘 https://global.sim.hashkeydev.com/sg

2. Go to Settings -> API Management -> Create API

3. Enter API Key name, select API permission and setup IP Access Restriction

Technical Support

General Inquiry

Operating hours: Monday to Friday, 9:00 AM to 6:00 PM HKT

Preferred method of contact: [email protected]

Please provide your inquiry in the following format:

Subject:

Environment: Production / Sandbox Inquiry

Identity: UID / Email

Request Body:

Question:

Emergency Production Trading issue

Operating hours: 7 * 24

For urgent matters during non-office hours, please log in to hashkey.com and contact our online Customer Support team via instant message widget.

REST API

Get Started

Python [POST] Order Submit sample

import time
import requests
import hashlib
import hmac
import json
from urllib.parse import urlencode

"""
####################################################################################################################################
# Test REST API
#
# Copyright: Hashkey Trading 2024 All rights reserved.
# Please note the API code is provided "As Is" basis, without warranty of any kind, either express or implied, including
# without limitation, warranties that the API code is free of defects, merchantable, non-infringing or fit for a particular purpose
####################################################################################################################################
"""

class RestAPIClient:
    def __init__(self, base_url, user_key, user_secret):
        """
        Initialize the RestAPIClient with base URL, user key, and user secret.

        Args:
            base_url (str): The base URL of the API.
            user_key (str): The user key for authentication.
            user_secret (str): The user secret for authentication.
        """
        self.base_url = base_url
        self.user_key = user_key
        self.user_secret = user_secret
        self.headers = {
            'X-APIKEY': user_key,
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        }

    def get_timestamp(self):
        """
        Get the current timestamp in milliseconds.

        Returns:
            int: The current timestamp.
        """
        return int(time.time() * 1000)

    def create_signature(self, content):
        """
        Create HMAC signature for authentication.

        Args:
            content (str): The content to be signed.

        Returns:
            str: The HMAC signature.
        """
        content_bytes = content.encode('utf-8')
        hmac_digest = hmac.new(
            self.user_secret.encode('utf-8'),
            content_bytes,
            hashlib.sha256
        ).hexdigest()
        return hmac_digest

    def place_order(self, symbol, side, order_type, quantity, price=None):
        """
        Place an order.

        Args:
            symbol (str): The trading pair symbol (e.g., ETHUSD).
            side (str): The order side (BUY or SELL).
            order_type (str): The order type (LIMIT or MARKET).
            quantity (str): The order quantity.
            price (str, optional): The order price (required for LIMIT orders).

        Returns:
            dict or None: The JSON response if successful, None otherwise.
        """
        timestamp = self.get_timestamp()
        data = {
            "symbol": symbol,
            "side": side,
            "type": order_type,
            "price": price,
            "quantity": quantity,
            "timestamp": timestamp
        }
        if order_type == 'MARKET':
            del data['price']

        data_string = urlencode(data)
        signature = self.create_signature(data_string)
        data['signature'] = signature

        response = requests.post(
            f"{self.base_url}/api/v1.1/spot/order",
            headers=self.headers,
            data=data
        )

        if response.status_code == 200:
            response_json = response.json()
            print("Response:")
            print(json.dumps(response_json, indent=4))  # Print formatted JSON response
            return response_json
        else:
            try:
                error_json = response.json()
                print("Error:")
                print(json.dumps(error_json, indent=4))  # Print formatted error response
            except json.JSONDecodeError:
                print(f"Error: {response.status_code} - {response.text}")
            return None

if __name__ == '__main__':
    # Example usage:
    # Create an instance of RestAPIClient with your API credentials
    # For Production account please change base_url to  https://api-pro.hashkey.com
    api_client = RestAPIClient(
        base_url="https://api-pro.sim.hashkeydev.com",
        user_key="your_user_key",
        user_secret="your_user_secret"
    )
    # Place an order with the desired parameters
    api_client.place_order("ETHUSDT", "BUY", "LIMIT", "0.01", "3000")

Python [GET] Account balance sample

import time
import requests
import hashlib
import hmac
import json

"""
####################################################################################################################################
# Test REST API
#
# Copyright: Hashkey Trading 2024 All rights reserved.
# Please note the API code is provided "As Is" basis, without warranty of any kind, either express or implied, including
# without limitation, warranties that the API code is free of defects, merchantable, non-infringing or fit for a particular purpose
####################################################################################################################################
"""

class RestAPIClient:
    def __init__(self, base_url, user_key, user_secret):
        """
        Initialize the RestAPIClient with base URL, user key, and user secret.

        Args:
            base_url (str): The base URL of the API.
            user_key (str): The user key for authentication.
            user_secret (str): The user secret for authentication.
        """
        self.base_url = base_url
        self.user_key = user_key
        self.user_secret = user_secret
        self.headers = {
            'X-APIKEY': user_key,
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        }

    def get_timestamp(self):
        """
        Get the current timestamp in milliseconds.

        Returns:
            int: The current timestamp.
        """
        return int(time.time() * 1000)

    def create_signature(self, content):
        """
        Create HMAC signature for authentication.

        Args:
            content (str): The content to be signed.

        Returns:
            str: The HMAC signature.
        """
        content_bytes = content.encode('utf-8')
        hmac_digest = hmac.new(
            self.user_secret.encode('utf-8'),
            content_bytes,
            hashlib.sha256
        ).hexdigest()
        return hmac_digest

    def get_account_info(self):
        """
        Get account information.

        Returns:
            dict or None: The JSON response if successful, None otherwise.
        """
        timestamp = self.get_timestamp()
        data = {
            "timestamp": timestamp
        }
        query_string = '&'.join([f"{key}={value}" for key, value in data.items()])
        signature = self.create_signature(query_string)

        response = requests.get(
            f"{self.base_url}/api/v1/account?{query_string}&signature={signature}",
            headers=self.headers
        )

        if response.status_code == 200:
            response_json = response.json()
            print("Response:")
            print(json.dumps(response_json, indent=4))  # Print formatted JSON response
            return response_json
        else:
            try:
                error_json = response.json()
                print("Error:")
                print(json.dumps(error_json, indent=4))  # Print formatted error response
            except json.JSONDecodeError:
                print(f"Error: {response.status_code} - {response.text}")
            return None

if __name__ == '__main__':
    # Example usage:
    # Create an instance of RestAPIClient with your API credentials
    # For Production account please change base_url to  https://api-pro.hashkey.com
    api_client = RestAPIClient(
        base_url="https://api-pro.sim.hashkeydev.com",
        user_key="your_user_key",
        user_secret="your_user_secret"
    )
    # Get account information
    api_client.get_account_info()

Sandbox Environment

Production Environment


General API Information


Access Restrictions


Order Rate Limiting


Endpoint Security Types


API-KEY Management

Authentication

Endpoint security type

API requests are likely to be tampered during transmission through the internet. To ensure that the request remains unchanged, all private interfaces other than public interfaces (basic information, market data) must be verified by signature authentication via API-KEY to make sure the parameters or configurations are unchanged during transmission.

Each created API-KEY need to be assigned with appropriate permissions in order to access the corresponding interface. Before using the interface, users is required to check the permission type for each interface and confirm there is appropriate permissions.

Authentication Type Description
NONE Endpoints are freely accessible
TRADE Endpoints requires sending a valid API-KEY and signature
USER_DATA Endpoints requires sending a valid API-KEY and signature
USER_STREAM The endpoints requires sending a valid API-KEY
MARKET_DATA The endpoints requires sending a valid API-KEY

Signature Authentication

Signature

TRADE & USER_DATA

All HTTP requests to API endpoints require authentication and authorization. The following headers should be added to all HTTP requests:

Key Value Type Description
X-APIKEY API-KEY string The API Access Key you applied for

Time-base security requirement

If your timestamp is ahead of serverTime it needs to be within 1 second + serverTime

The logic of this parameter is as follows:

 if (timestamp < (serverTime + 1000) && (serverTime - timestamp) <= recvWindow) {
    // process request
  } else {
    // reject request
  }

Example 1: In queryString

symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000

echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"

Shell standard output:

5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6

curl -H "X-HK-APIKEY: tAQfOrPIZAhym0qHISRt8EFvxPemdBm5j5WMlkm3Ke9aFp0EGWC2CGM8GHV4kCYW" -X POST 'https://$HOST/api/v1/spot/order?symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000&signature=5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6'

Example 2: In the request body

symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000

echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"

Shell standard output:

5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6

curl -H "X-HK-APIKEY: tAQfOrPIZAhym0qHISRt8EFvxPemdBm5j5WMlkm3Ke9aFp0EGWC2CGM8GHV4kCYW" -X POST 'https://$HOST/api/v1/spot/order' -d 'symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000&signature=5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6'

Example 3: mixing queryString and request body

symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC

quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000

echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTCquantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"

Shell standard output:

885c9e3dd89ccd13408b25e6d54c2330703759d7494bea6dd5a3d1fd16ba3afa

curl -H "X-HK-APIKEY: tAQfOrPIZAhym0qHISRt8EFvxPemdBm5j5WMlkm3Ke9aFp0EGWC2CGM8GHV4kCYW" -X POST 'https://$HOST/openapi/v1/order?symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC' -d 'quantity=1&price=0.1&recvWindow=5000&timestamp=1538323200000&signature=885c9e3dd89ccd13408b25e6d54c2330703759d7494bea6dd5a3d1fd16ba3afa'

Account

Get Account Information

GET /api/v1/account

Retrieve account balance

Weight: 5

Request Parameters

PARAMETER TYPE Req'd Example values DESCRIPTION
accountId LONG Y 1471090223379184384 Account ID, for Master Key only (Master Key users can check sub trading account information by inputing sub trading accountId)
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "balances": [
    {
      "asset": "BTC",
      "assetId": "BTC",
      "assetName": "BTC",
      "total": "333.805297855",
      "free": "333.775297855",
      "locked": "0.03"
    },
    {
      "asset": "ETH",
      "assetId": "ETH",
      "assetName": "ETH",
      "total": "239.2252562",
      "free": "239.2252562",
      "locked": "0"
    },
    {
      "asset": "HKD",
      "assetId": "HKD",
      "assetName": "HKD",
      "total": "9775428.24",
      "free": "9775428.24",
      "locked": "0"
    },
    {
      "asset": "USD",
      "assetId": "USD",
      "assetName": "USD",
      "total": "8180584.8854663502",
      "free": "8177843.2054663502",
      "locked": "2741.68"
    },
    {
      "asset": "USDC",
      "assetId": "USDC",
      "assetName": "USDC",
      "total": "12684763.712318516",
      "free": "12684763.712318516",
      "locked": "0"
    },
    {
      "asset": "USDT",
      "assetId": "USDT",
      "assetName": "USDT",
      "total": "91579.017554413172",
      "free": "91579.017554413172",
      "locked": "0"
    }
  ],
  "userId": "4014986192463421361"
}
PARAMETER TYPE Example values DESCRIPTION
balances Object Array Query an asset array
balances.asset STRING BTC Assets
balances.assetId STRING BTC Asset ID
balances.assetName STRING BTC Asset Name
balances.total STRING 100.63264 Total available funds
balances.free STRING 100.63264 Available funds
balances.locked STRING 0 Frozen funds
userId STRING 4014986192463421361 User ID

Query Account Type

GET /api/v1/account/type

Account Type

accountType Type
1 Trading Account
3 Future Account
5 Custody Account
6 Fiat Account
7 OPT Account

Weight: 5

Request Parameters

PARAMETER TYPE Req'd Example values DESCRIPTION
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

[
  {
    "accountId": "1954336770171707136",
    "accountLabel": "Main Trading Account",
    "accountType": 1,
    "accountIndex": 0,
    "userId": "1954336770188484352"
  },
  {
    "accountId": "1954336770171707137",
    "accountLabel": "Custody Account",
    "accountType": 5,
    "accountIndex": 0,
    "userId": "1954336770188484352"
  },
  {
    "accountId": "1954336770171707138",
    "accountLabel": "Fiat Account",
    "accountType": 6,
    "accountIndex": 0,
    "userId": "1954336770188484352"
  },
  {
    "accountId": "2076829658620461312",
    "accountLabel": "OPT Account",
    "accountType": 7,
    "accountIndex": 0,
    "userId": "1954336770188484352"
  },
  {
    "accountId": "1954346689088298752",
    "accountLabel": "Sub Main Trading Account",
    "accountType": 1,
    "accountIndex": 0,
    "userId": "1954346688375497216"
  },
  {
    "accountId": "1954346689088298753",
    "accountLabel": "Sub Custody Account",
    "accountType": 5,
    "accountIndex": 0,
    "userId": "1954346688375497216"
  }
]
PARAMETER TYPE Example values DESCRIPTION
* Object Array Query subaccount results
accountId STRING 1954336770171707136 Account Number
accountLabel STRING Custody Account Account Label
accountType INTEGER 1 Account Type
accountIndex INTEGER 0
userId STRING 1954336770188484352 UserId of the account

Internal Account Transfer

This endpoint should be called no more than once per second.

POST /api/v1/account/assetTransfer

Internal asset account transfer. Need to grant the account with "Read/Write Permissioin - Allow internal transfer" authority.

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd Example values DESCRIPTION
fromAccountId STRING Y 1467296062716909568 Source Account ID
toAccountId STRING Y 1473231491689395200 Destinate Account ID
coin STRING Y USDT Coin
quantity STRING(DECIMAL) Y 20 Transfer amount
remark STRING TestingRemark Remark
clientOrderId STRING 12345678 Client unique order identifier (up to 64 characters)
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1712317312973 Timestamp

Response Content

{
  "success": true,
  "timestamp": 1716048391349,
  "clientOrderId": "",
  "orderId": "1688730736494914304"
}
PARAMETER TYPE Example values DESCRIPTION
success BOOLEAN TRUE Whether successful
timestamp LONG 1699943911155 Transfer completed time
clientOrderId STRING 12345678 Client unique order identifier
orderId STRING 1555687946987836672 Transfer Order ID
(Same as Fund statement orderId for transfer)

Get API Key Type

GET /api/v1/account/checkApiKey

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example values DESCRIPTION
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "accountType": "Master Account"
}
PARAMETER TYPE Example values DESCRIPTION
accountType STRING Master Account
Sub Account
Account Type

Wallet

Get Deposit Address

GET /api/v1/account/deposit/address

Retrieve deposit address generated by the system. Usually used when fromAddress is already in depositing white list.
If you need to get small amount for verification, please refer to Get Verify Whitelist Address

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd Example values DESCRIPTION
coin STRING Y USDT Coin name
chainType ENUM Y ETH Pls refer to:Get ChainType
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "canDeposit": true,
  "address": "mock0x7e9dc38bec1542228e02e46e6f8cddd0",
  "addressExt": "",
  "minQuantity": "0.001",
  "needAddressTag": false,
  "requiredConfirmTimes": 64,
  "canWithdrawConfirmTimes": 64,
  "coinType": "CHAIN_TOKEN"
}
PARAMETER TYPE Example values DESCRIPTION
canDeposit BOOLEAN true Can be deposited
address STRING 0x7c07adb0D2DE76241b262595860b16Cf90615aa0 Deposit Address
addressExt STRING Tag (Not in use)
minQuantity STRING 0.001 Minimum Amount to be deposited
needAddressTag BOOLEAN false Is address tag required (Not in use)
requiredConfirmTimes INTEGER 64 Credit to account block confirmation (Reference only)
canWithdrawConfirmTimes INTEGER 64 Withdrawal block confirmation (Reference only)
coinType STRING CHAIN_TOKEN Coin Type

Get Deposit History

GET /api/v1/account/depositOrders

Deposit Status

Deposit Type Description
1 Pending address authentication 待地址认证
3 Deposit failed 充值失败
4 Deposit successful 充值成功
5 Refunding 退币中
6 Refund completed 退币完成
7 Refund failed 退币失败
8 In the account 上账中
12 Deposit processing 充值中

Weight: 5

Request Parameters

PARAMETER TYPE Req 'd Example values DESCRIPTION
coin STRING ETH_USDT Chain_Coin
startTime LONG 16500121212121 Start timestamp
endTime LONG 16600131311313 End timestamp
fromId INTEGER 123456 Starting ID
limit INTEGER 500 Default 500; Max 1000
depositOrderId STRING Deposit order ID Do not support Batch.
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

[
  {
    "time": "1761145627173",
    "depositOrderId": "D768973742990266368",
    "coin": "USDT",
    "coinName": "USDT",
    "address": "usdttro1021",
    "addressExt": "",
    "quantity": "8988.99990000000000000000",
    "status": 4,
    "statusCode": "4",
    "txId": "37edcfeac8533be4fd1eb83ec4d84cadee877ae4cd738bb59af226ddfc2b31ed",
    "walletId": "1978966613676937217",
    "clientOrderId": "",
    "refundCode": "",
    "refundReason": "",
    "failureReason": "",
    "chainType": "Tron"
  }
]
PARAMETER TYPE Example values DESCRIPTION
time STRING 1691048298420 Deposit order created Timestamp
depositOrderId STRING D578755281141776384 Deposit order ID
clientOrderId STRING REF-20250428-ETH-789012 The unique ID assigned by the client
coin STRING ETH Coin
coinName STRING ETH Coin name
address STRING 0xa0D6AD420C440de473980117877DEC0a89DAFbeF Deposit address
addressExt STRING 123456 "addressExt is a unique code used to identify a specific account or user, ensuring that funds are sent to the correct recipient.Other exchanges or wallets may refer to Memo as Digital ID, Tag, Memo, Note, Remark, or Comment."
quantity STRING (decimal) 0.05000000000000000000 Deposit amount
status ENUM 4 Deposit status
statusCode ENUM 4 Same as status
txId STRING 0xbd40b38543767a7d441c87c676ddfaf6cf750e4c7d8d66abd0f1665eb031932a On-chain transaction ID
failureReason STRING We do not accept deposits from third party exchanges Failure Reason
chainType STRING Tron

Get Verify Whitelist Address

GET /api/v1/whitelist/verify

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd Example Values DESCRIPTION
coin STRING Y USDT Coin name
chainType ENUM Y USDT_ETH Coin_Chain
quantity STRING Y 0.1 Deposit Amount
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "coin": "USDT",
  "depositAddress": "mock0xa9df1c177b4e4f2bb1a180352e9ed663",
  "depositAmount": "250.10000000000000000000",
  "addressExt": "",
  "chainType": "Tron"
}
PARAMETER TYPE Example Values DESCRIPTION
coin STRING BTC Coin name
depositAddress STRING 0x7c07adb0D2DE76241b262595860b16Cf90615aa0 Deposit Address (To)
depositAmount STRING 0.0004 HashKey specified random deposit amount
addressExt STRING Other exchanges or wallets may refer to Memo as Digital ID, Tag, Memo, Note, Remark, or Comment. AddressExt is a unique code used to identify a specific account or user, ensuring that funds are sent to the correct recipient.
chainType STRING Tron

Get Whitelisted Address

GET /api/v1/account/whitelistAddress

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd Example Values DESCRIPTION
coin STRING Y USDT_ETH Coin_ChainType
type STRING Y Deposit Deposit or Withdraw
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

[
  {
    "fromAddress": "0xb85f1c7a091ab20f85655e9cde09c9d1d68903d1",
    "coin": "USDT",
    "chainType": "USDT_ETH"
  }
]
PARAMETER TYPE Example Values DESCRIPTION
* Object Array
fromAddress STRING 0x5507D17587310aD5e71408BDD494003c7D3d0947 Whitelisted Address
coin STRING USDT Coin name
chainType STRING USDT_Tron Coin_ChainType

Withdraw VA

POST /api/v1/account/withdraw

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example Values DESCRIPTION
coin STRING Y USDT Assets
clientOrderId STRING Y w12912 Custom Withdrawal ID (up to 255 characters)
address STRING Y 0x132346ef629483974879a2e68A3557cA1c494D2E Withdrawal address
addressExt STRING - Tag (Not in use)
quantity DECIMAL Y 0.2 Withdrawal amount
chainType STRING Y ETH Chain Type
remark STRING Test Remark
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "success": true,
  "id": "0",
  "orderId": "W778315027390844928",
  "accountId": "1954346809338994433",
  "clientOrderId": "",
  "platform": ""
}
PARAMETER TYPE Example Values DESCRIPTION
success BOOELEAN true Error code
platform STRING "HashKey" Target Trading Platform of the withdrawal
id STRING 0 ID
orderId STRING W579805129870495744 Order ID
accountId STRING 1644290379632090369 Wallet ID
clientOrderId STRING w12912 Custom Withdrawal ID

Get Withdraw History

GET /api/v1/account/withdrawOrders

Weight: 5

Request Parameters

PARAMETER TYPE Req 'd Example values DESCRIPTION
coin STRING ETH_USDT Chain_Coin
startTime LONG 16500121212121 Start timestamp
endTime LONG 16600131311313 End timestamp
remark STRING Test Remark
limit INTEGER 500 Default 500; Max 1000
clientOrderId STRING Client order ID Custom Withdrawal ID
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

[
  {
    "time": "1761188149478",
    "id": "W769152094447452160",
    "coin": "USDT",
    "coinId": "USDT",
    "coinName": "USDT",
    "address": "usdtTronreal",
    "addressExt": "",
    "quantity": "180.00000000",
    "arriveQuantity": "180.00000000",
    "status": "successful",
    "txId": "3dafba8abd7a7b2d02ac9161b41313931c9bafa18cf8cec2c98b1a4ec300be32",
    "addressUrl": "usdtTronreal",
    "feeCoinId": "USDT",
    "feeCoinName": "USDT",
    "fee": "0.00010000",
    "remark": "",
    "failedReason": "",
    "clientOrderId": "usdttron102303",
    "platform": "",
    "chainType": "Tron"
  }
]
PARAMETER TYPE Example Values DESCRIPTION
* Object Array Query result list
time STRING 1691053667700 Timestamp
id STRING W474986756938121216 Withdrawal order ID
coin STRING ETH Coin
coinId STRING ETH Coin ID
coinName STRING ETH Coin Name
address STRING 0xa0d6ad420c440de473980117877dec0a89dafbef Withdrawal Address
addressExt STRING 123456 addressExt is a unique code used to identify a specific account or user, ensuring that funds are sent to the correct recipient.
Other exchanges or wallets may refer to Memo as Digital ID, Tag, Memo, Note, Remark, or Comment.
quantity STRING (decimal) 0.05000000 Withdrawal amount entered by the user
arriveQuantity STRING (decimal) 0.05000000 Net amount received
status STRING successful Status:
- failed
- withdrawing
- successful
- canceled
- canceling
failedReason STRING KYT_FAILED KYT_FAILED
ASSET_FROZEN_FAILED
ONCHAIN_FAILED
txId STRING 0x448345d7d95614e19ad2c499be451cdec8d9fa109889f4dab201e3e50f0a06b4 Transaction ID
addressUrl STRING 0xa0d6ad420c440de473980117877dec0a89dafbef Withdrawal address URL (Same as address)
feeCoinId STRING ETH Fee Currency ID
feeCoinName STRING ETH Fee Currency Name
fee STRING 0.00600000 Handling fee
remark STRING Remark
clientOrderId STRING w12912 Custom Withdrawal ID
chainType STRING ETH Chain Type

Get ChainType

GET /api/v1/account/chainType

Get the supported list of ChainType for a specific CoinId(e.g. ETH) ChainType is typically used when deposit & withdrawal

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example values DESCRIPTION
coinId STRING Y USDT Coin Name. e.g: "BTC", "ETH"
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

[
  {
    "coinId": "USDT",
    "coinName": "USDT",
    "chainTypeList": [
      "ETH",
      "Tron"
    ]
  }
]
PARAMETER TYPE Example values DESCRIPTION
* Object Array
coinId STRING USDT Coin Name
coinName STRING USDT Coin Name
chainTypeList LIST ["ETH","Tron"] List of supported chain types.

Market Place

Get MP Quote Pairs

GET /api/v1/market-place/get-pairs

Get a list of tradable quote pairs

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example Values DESCRIPTION
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1714311403031 Timestamp

Response Content

{
  "quotePair": [
    {
      "baseCcy": "USDC",
      "quoteCcy": "USD",
      "basePrecision": "0.0001",
      "quotePrecision": "0.01",
      "retailAllowed": false,
      "minTradeBaseQuantity": "1.65",
      "maxTradeBaseQuantity": "100000",
      "minTradeQuoteQuantity": "10",
      "maxTradeQuoteQuantity": "100000",
      "piAllowed": true,
      "corporateAllowed": true,
      "omnibusAllowed": true,
      "institutionAllowed": true,
      "tradingStatus": "OPENED"
    },
    {
      "baseCcy": "BTC",
      "quoteCcy": "USDT",
      "basePrecision": "0.00001",
      "quotePrecision": "0.00001",
      "retailAllowed": true,
      "minTradeBaseQuantity": "0.001",
      "maxTradeBaseQuantity": "10000000",
      "minTradeQuoteQuantity": "10",
      "maxTradeQuoteQuantity": "10000000",
      "piAllowed": true,
      "corporateAllowed": true,
      "omnibusAllowed": true,
      "institutionAllowed": false,
      "tradingStatus": "OPENED"
      "isSTO": 0
    },
    {
      "baseCcy": "ETH",
      "quoteCcy": "USDT",
      "basePrecision": "0.0001",
      "quotePrecision": "0.0001",
      "retailAllowed": false,
      "minTradeBaseQuantity": "0",
      "maxTradeBaseQuantity": "37.0548",
      "minTradeQuoteQuantity": "1",
      "maxTradeQuoteQuantity": "100000",
      "piAllowed": true,
      "corporateAllowed": true,
      "omnibusAllowed": true,
      "institutionAllowed": true,
      "tradingStatus": "OPENED",
      "isSTO": 0
    }
  ]
}
Parameter Type Example Value Description
quotePair Object Array ETHUSD Returns a list of currency pairs for Request for Quote
baseCcy STRING ETH Base currency
quoteCcy STRING USD Quote currency
basePrecision STRING 0.0001 Precision of base currency
quotePrecision STRING 0.000001 Precision of quote currency
retailAllowed BOOLEAN TRUE Whether retail clients are allowed
minTradeBaseQuantity STRING 10000 minTradeQuantity of baseCcy defined in OPM
maxTradeBaseQuantity STRING 1000000 maxTradeQuantity of baseCcy defined in OPM
minTradeQuoteQuantity STRING 10000 minTradeQuantity of quoteCcy defined in OPM
maxTradeQuoteQuantity STRING 1000000 maxTradeQuantity of quoteCcy defined in OPM
piAllowed BOOLEAN TRUE Whether PI clients are allowed
corporateAllowed BOOLEAN TRUE Whether Corporate clients are allowed
omnibusAllowed BOOLEAN TRUE Whether Omnibus clients are allowed
institutionAllowed BOOLEAN TRUE Whether Institution clients are allowed
tradingStatus ENUM OPENED, CLOSED Quote pair status
isSTO INT 0 is STO token

Create MP RFQ

POST /api/v1/market-place/create-rfq

Customer creates the RFQ

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example DESCRIPTION
rfqClOrderId STRING C RFQ12345666 (Optional) An ID defined by the client for the quote order. It will be automatically generated if not sent in the request.
buyCcy STRING Y BTC
sellCcy STRING Y USDT
sellAmount DECIMAL Y 130000 Selling amount
rfqMode STRING Y real-time, delayed
expireSec INT 1800 RFQ valid period in seconds, default 1800 = 30 minutes, allowed 10–60 mins
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1714311403031 Timestamp

Response Content

{
  "rfqId": "RFQ638459562162049024",
  "rfqClOrderId": "RFQ12345666",
  "status": "new"
}
PARAMETER TYPE Example values DESCRIPTION
rfqClOrderId STRING RFQ12345666 (Optional) An ID defined by the client for the quote order. It will be automatically generated if not sent in the request.
rfqId STRING RFQ638459562162049024 A unique reference ID for this quote.
status STRING new

Accept MP Quote

POST /api/v1/market-place/accept-quote

Customer accepts the quote

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example DESCRIPTION
quoteId STRING Y quote789456123 The unique quote id auto generated for each quote when creation
rfqId STRING Y rfq638459562162049024 A unique reference ID for this quote.
action STRING Y accept, decline decline only works for manual order (after decline, rfq becomes failed)
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1714311403031 Timestamp

Response Content

{
  "rfqId": "rfq638459562162049024",
  "quoteId": "quote789456123",
  "status": "accepted",
  "expiryTime": 1717392500
}
PARAMETER TYPE Example values DESCRIPTION
quoteId STRING quote789456123 The unique quote id auto generated for each quote when creation
rfqId STRING rfq638459562162049024 A unique reference ID for this quote.
status STRING accepted
expiryTime LONG 1800 Min of quote and rfq expiry time, if action = decline,expiryTime will be null

Get MP RFQ history

GET /api/v1/market-place/rfqs

Customer check the RFQ history

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example DESCRIPTION
rfqId STRING 122456 The orderId generated by HashKey. If not specified, will return all records.
quoteId STRING The unique quote id auto generated for each quote when creation
rfqClOrderId STRING 122455 A client-defined ID for the order, autogenerated if not specified.
limit INT Limit per page for records. - Default: 500, Max: 1000.
status ENUM new status filter
startTime LONG Y 1764645641000 createTime filter, max last 90 days
endTime LONG Y 1766373641000 createTime filter, max last 90 days
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1714311403031 Timestamp

Response Content

[
  {
    "rfqCreateTime": 1716002500,
    "rfqId": "RFQ638459562162049024",
    "quoteId": "QUOTE_789456123",
    "rfqClOrderId": "QUOTE_789456123",
    "rfqMode": "real-time",
    "quoteMode": "real-time",
    "buyCcy": "BTC",
    "sellCcy": "USDT",
    "buyAmount": "2",
    "sellAmount": "",
    "price": "65000",
    "status": "successful",
    "executedTime": 1717392500
  }
]
PARAMETER TYPE Example values DESCRIPTION
rfqCreateTime LONG 1617315200 Timestamp that the rfg was created
rfqId STRING 122456 The unique orderId generated by HashKey.
quoteId STRING The unique quote id auto generated for each quote when creation
rfqClOrderId STRING 122455 A client-defined ID for the order, autogenerated if not specified.
rfqMode STRING
quoteMode STRING
buyCcy STRING
sellCcy STRING
buyAmount STRING
sellAmount STRING
price STRING
status ENUM new new : active
accepted : quote accepted
processing : On-chain/funds are locked (Real-time orders will be executed immediately, while delayed orders will remain in this status pending settlement, up to T+2)
successful : Settlement successful
expired : Quote expired
cancelled : Cancelled by HSK operations
declined : Manual quote rejected by the quoting party
manual-order : Awaiting manual quote
manual-order-confirmation : Manual quote received, awaiting confirmation from the quoting party
executedTime LONG Timestamp that the rfq was executed and status = successful

Get all Active MP Quotes

GET /api/v1/market-place/rfq-active/{rfqId}

Customer check the RFQ history

Weight: 1

Request Parameters

PARAMETER TYPE Req'd Example DESCRIPTION
rfqId (path parameter) STRING Y 123456 The orderId generated by HashKey.
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y 1714311403031 Timestamp

Response Content

[
  {
    "quoteMode": "REAL_TIME",
    "sellCcy": "USD",
    "rfqId": "MP740508620175265792",
    "quoteId": "MPQ740508741768138752",
    "rfqClOrderId": "MP740508620175265792",
    "buyCcy": "BTC",
    "rfqMode": "REAL_TIME",
    "buyAmount": "0.00009",
    "expireTime": 1754359101795,
    "sellAmount": "10",
    "price": "101000",
    "rank": 1,
    "status": "new"
  },
  {
    "quoteMode": "REAL_TIME",
    "sellCcy": "USD",
    "rfqId": "MP740508620175265792",
    "quoteId": "MPQ740508741768138792",
    "rfqClOrderId": "MP740508620175265792",
    "buyCcy": "BTC",
    "rfqMode": "REAL_TIME",
    "buyAmount": "0.00009",
    "expireTime": 1754359101795,
    "sellAmount": "10",
    "price": "102000",
    "rank": 2,
    "status": "new"
  }
]
PARAMETER TYPE Example values DESCRIPTION
quoteMode STRING
sellCcy STRING
rfqId STRING
quoteId STRING
rfqClOrderId STRING
buyCcy STRING
rfqMode STRING
buyAmount STRING
expireTime LONG
sellAmount STRING
price STRING
rank INTEGER
status STRING

Miscellaneous

Test Connectivity

GET /api/v1/ping

Test connectivity to ensure valid Status 200 OK

Weight: 1

Request Parameters

Empty

Response Content

{}

{}

Check Server Time

GET /api/v1/time

Test the connection and returns the current server time (in UNIX timestamp in milliseconds)

Weight: 1

Request Parameters

Empty

Response Content

{
  "serverTime": 1764229341307
}
PARAMETER TYPE Example values DESCRIPTION
serverTime LONG 1764229341307 Server Millisecond Timestamp

Create Listen Key

POST /api/v1/userDataStream

Create a single Listen Key. Valid for 60 minutes.

Reminder

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd DESCRIPTION
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{
  "listenKey": "MKxPTRoLXBBhlRseAUaDyWyZVjiNxCVqcaUasZidmByckGjUcLBKKcopKbvUfORD"
}
PARAMETER TYPE Example Values DESCRIPTION
listenKey STRING MKxPTRoLXBBhlRseAUaDyWyZVjiNxCVqcaUasZidmByckGjUcLBKKcopKbvUfORD Key to subscribe websocket feeds

Reset Listen Key

PUT /api/v1/userDataStream

Reset validity time of a listenKey to 60 minutes.

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd DESCRIPTION
listenKey STRING Y Key to reset
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{}

{}

Delete Listen Key

DELETE /api/v1/userDataStream

Delete a single Listen Key.

Weight: 1

Request Parameters

PARAMETER TYPE Req 'd DESCRIPTION
listenKey STRING Y Key to delete
recvWindow LONG Recv Window. Default 5000
timestamp LONG Y Timestamp

Response Content

{}

{}

Error Codes

List of error codes

ERROR CODE HTTP Status Code ERROR MESSAGE DESCRIPTION
200 200 Success request
0000 200 success Success request
0001 400 Required field %s missing or invalid Required field %s missing or invalid. E.g. Required field quantity missing or invalid
0001 400 Incorrect signature The server is not able to valid your signature request. Please check your signature whether it have the correct signing.
0003 400 Rate limit exceeded Rate limit exceed per configuration. Please manage the number of your request
0102 400 Invalid APIKey There was an issue validating your API Key permission. Please check your API Key permission
0103 400 APIKey expired API-key has expired. Please login to Account management console to renew the API key
0104 400 accountId is not allowed The accountId defined is not permissible
0201 400 Instrument not found The instrument defined cannot be located
0202 400 Invalid IP Our server detected the IP addresses submitted for the API request does not match API key whitelisted IP address
0206 400 Unsupported order type Invalid order type being sent to the server
0207 400 Invalid price Invalid price being sent to the server
0209 400 Invalid price precision The precision price is over the maximum allowed for this asset
0210 400 Price outside of allowed range Price of the order below minPrice or exceeds maxPrice range. Please check exchangeInfo
0211 400 Order not found Our server not able to locate the orderId defined
0212 400 Order has already been completed (filled, canceled, etc) or does not exist. Please check the order status to verify Order has already been completed (filled, canceled, etc) or does not exist. Please check the order status to verify
0401 400 Insufficient asset There is insufficient balance to submit the order
-1000 400 An unknown error occurred while processing the request An issue generated by our server
-1001 400 Internal error Unable to process your request. Please try again
-1002 400 Unauthorized operation Server is not able to validate your API Key. Please ensure you have the valid API Key to the corresponding environment
-1004 400 Bad request There was an issue with to process your request. Please check your parameters or values are valid
-1005 400 No permission It appears there is insufficient trading permission. Please check your permission
-1006 400 Execution status unknown An unexpected response was received from the message bus
-1007 400 Timeout waiting for response from server Timeout waiting for response from backend server. Send status unknown; execution status unknown
-1014 400 Unsupported order combination The order combination specified is not supported
-1015 400 Too many new orders, current limit is %s orders per %s Reach the rate limit .Please slow down your request speed. Too many new orders.
-1020 400 Unsupported operation User operation is not supported
-1021 400 Timestamp for this request is outside of the recvWindow Timestamp for this request was 1000ms ahead of the server's time. Please check the difference between your local time and server time
-1024 400 Duplicate request Duplicate request received
-1101 400 Feature has been offline Feature has been offline, please check with API team for further details
-1115 400 Invalid timeInForce Invalid time in force being sent
-1117 400 Invalid order side Invalid side being sent
-1123 400 Invalid client order id Invalid client order ID being sent
-1124 400 Invalid price Invalid price being sent
-1126 400 Invalid quantity Invalid quantity being sent
-1129 400 Invalid parameters, quantity and amount are not allowed to be sent at the same time. The combination of quantity and amount is not allowed to be submitted at the same time
-1130 400 Illegal parameter %s Invalid data sent for a parameter. E.g. "Illegal parameter 'symbol'"
-1132 400 Order price greater than the maximum Order price exceeds maxPrice. Check ExchangeInfo
-1133 400 Order price lower than the minimum Order price below the threshold minPrice. Check ExchangeInfo
-1135 400 Order quantity greater than the maximum Order quantity exceeds the maxQty. Check ExchangeInfo
-1136 400 Order quantity lower than the minimum Order quantity below threshold minQty. Check ExchangeInfo
-1137 400 Order quantity precision too large Order quantity precision is too large
-1139 400 Order has been filled Unable to fulfill request as order has been filled
-1140 400 Order amount lower than the minimum The transaction amount is below the threshold minAmount. Check ExchangeInfo
-1141 400 Duplicate order The server have detected an existing clientOrderId sent before
-1142 400 Order has been cancelled Unable to fulfill rquest as order has been canceled
-1143 400 Order not found on order book Unable to locate orderbook
-1144 400 Order has been locked Order has been locked
-1145 400 Cancellation on this order type not supported This order type does not support cancellation
-1146 400 Order creation timeout Not able to create the order and timed out
-1147 400 Order cancellation timeout Not able to cancel the order and timed out
-1148 400 Order amount precision too large Market Cash Amount precision is too long
-1149 400 Order creation failed Order creation failed
-1150 400 Order cancellation failed Order cancellation failed
-1151 400 The trading pair is not open yet The trading is not yet listed for trading
-1152 400 User does not exist Unable to find user
-1153 400 Invalid price type Invalid price type being sent
-1154 400 Invalid position side Invalid side being sent
-1155 400 The trading pair is not available for api trading API trading is suspended for API trading
-1156 400 Limit maker order rejected: Improper price may cause immediate fill. Creation of limit maker order failed as the order execute immediately.For HashKey Global only.
-1160 400 Account does not exist Account does not exist
-1161 400 Balance transfer failed Transfer internal funds failed
-1162 400 Unsupport contract address Contract address submitted is not valid
-1163 400 Illegal withdrawal address Withdraw address is not valid
-1164 400 Withdraw failed Withdraw failed, check if the withdrawal amount meets the minimum withdrawal amount
-1165 400 Withdrawal amount cannot be null Withdrawal amount needs to be more than 0
-1166 400 Withdrawal amount exceeds the daily limit Withdrawal amount exceeded the daily limit allowed
-1167 400 Withdrawal amount less than the minimum Withdrawal amount less than the min withdraw amount limit
-1168 400 Illegal withdrawal amount Withdrawal amount characters are not valid
-1169 400 Withdraw not allowed Withdrawal is currently suspended
-1170 400 Deposit not allowed Deposit is currently suspended
-1171 400 Withdrawal address not in whitelist Withdrawal address has not yet been whitelisted
-1172 400 Invalid from account id The fromAccountId is invalid
-1173 400 Invalid to account id The toAccountId is invalid
-1174 400 Transfer not allowed between the same account The fromAccount should not be equal toAccount
-1175 400 Invalid fiat deposit status The fiat deposit status submitted is invalid
-1176 400 Invalid fiat withdrawal status The fiat withdrawal status submitted is invalid
-1177 400 Invalid fiat order type The fiat order type submitted is invalid
-1182 400 The newly whitelisted withdrawal address will take effect in 30 min. Please try it later. The newly whitelisted withdrawal address will take effect after a certain time period for the sake of safety. During the mean time, the address is not available
-1186 400 Placing orders via api is not allowed, please check the API permission Placing orders via api is not allowed, please check the API permission
-1193 400 Order creation count exceeds the limit Order count have exceeded the amount allowed
-1194 400 Market order creation forbidden Creation of market order is forbidden
-1200 400 Order buy quantity too small Buy limit quantity below the threshold minQty. Check ExchangeInfo
-1201 400 Order buy quantity too large Buy limit quantity exceeds maxQty. Check ExchangeInfo
-1202 400 Order sell quantity too small Sell limit quantity below the threshold minQty. Check ExchangeInfo
-1203 400 Order sell quantity too large Sell limit quantity exceeds the maxQty. Check ExchangeInfo
-1204 400 From account must be a main account Transfer fromAccountId needs to be a main account
-1205 400 Account not authorized Account is not authorised
-1206 400 Order amount greater than the maximum The transaction amount is below the threshold maxAmount. Check ExchangeInfo
-1207 400 The status of deposit is invalid The status of deposit submitted is invalid
-1208 400 The orderType of fiat is invalid The status of orderType is not valid
-1209 400 The status of withdraw is invalid The status of withdraw is not valid
-1210 400 The deposit amount %s must not be less than the minimum deposit amount %s %s. The deposit amount %s must not be less than the minimum deposit amount %s %s.
-1211 400 Withdrawal in progress Withdrawal in progress
-1212 400 The order of deposit does not exist The order of deposit does not exist
-1213 400 The status of deposit cannot apply refund The status of deposit cannot apply refund
-1214 400 The account of deposit does not exist The account of deposit does not exist
-1215 400 User account status is abnormal User account status is abnormal
-1300 400 Sorry we can not locate this depositOrderId, please check and try again. Sorry we can not locate this depositOrderId, please check and try again.
-1301 400 Please contact the support team for historical orders Please contact the support team for historical orders
-1302 400 The refund via api can not be processed due to order status, please contact support team The refund via api can not be processed due to order status, please contact support team
-1303 400 The refund request via api can not be processed due to failure reason, please contact support team The refund request via api can not be processed due to failure reason, please contact support team
-1304 400 Please upload supporting docs as required, only image files .jpg, .png, .jpeg allowed. Please upload supporting docs as required, only image files .jpg, .png, .jpeg allowed.
-1305 400 Image size exceeds 1M, please revise and try again Image size exceeds 1M, please revise and try again
-2010 400 Limit maker order rejected: Improper price may cause immediate fill. New order request was rejected. Usually this is due to new LIMIT_MAKER order not able to be maker, our system will auto reject the order For HashKey Hong Kong only
-2011 400 Order cancellation rejected Cancel request was rejected
-2016 400 API key creation exceeds the limit The number of API key created have exceeded the limit
-2017 400 Open orders exceeds the limit of the trading pair The number of open orders have exceeded the limit for the trading pair
-2018 400 Trade user creation exceeds the limit The number of trade user created have exceeded the limit
-2019 400 Trader and omnibus user not allowed to login app The trader and omnibus user is not allowed to login to the app
-2020 400 Not allowed to trade this trading pair Not allowed to trade this trading pair
-2021 400 Not allowed to trade this trading pair Not allowed to trade this trading pair
-2022 400 Order batch size exceeds the limit The number of orders in batchOrders request exceeds its limit
-2023 400 Need to pass KYC verification Need to pass KYC verification in order to use API trading
-2024 400 Fiat account does not exist Fiat account ID defined does not exist
-2025 400 Custody account not exist Custody account ID defined does not exist
-2026 400 Invalid type The type defined is invalid
-2027 400 Exceed maximum time range of 30 days The startTime and endTime defined for Fund statement request exceeds the 30 days limit
-2028 400 The search is limited to data within the last one month The search is limited to data within the last one month
-2029 400 The search is limited to data within the last three months The search is limited to data within the last three months
-2030 400 Order batch size exceeds the limit Order batch size exceeds the limit
-3002 400 Invalid channel value Invalid channel value
-3003 400 quote expired or sellAmount invalid, please check again quote expired or sellAmount invalid, please check again
-3117 400 Invalid permission Invalid permission is detected. E.g. APIKey does not have the accountID permission to query the balance of the account
-3143 400 Currently, your trading account has exceeded its limit and is temporarily unable to perform trades The trading account have exceeds its limit capacity. We have temporarily suspended your trading
-3144 400 Currently, your trading account has exceeded its limit and is temporarily unable to perform transfers The trading account have exceeds its limit capacity. We have temporarily suspended your transfer
-3145 400 Please DO NOT submit request too frequently We have detected the rate of your API request have been submitted too frequently. Please manage your API request.
-4000 400 Invalid bank account number Invalid bank account number
-4001 400 Invalid asset The asset specified is invalid
-4002 400 Withdrawal amount less than the minimum withdrawal amount The withdrawal amount submitted is less than the minimum amount
-4003 400 Insufficient Balance There was insufficient balance for the asset you are trying to withdraw
-4004 400 Invalid bank account number The bank account has not been whitelisted yet
-4005 400 Assets are not listed Assets are not listed
-4006 400 Kyc is not certified The user has not passed KYC
-4007 400 Withdrawal channels are not supported The withdrawal channel is not yet supported via API
-4008 400 This currency does not support this customer type The currency is not supported for the client type
-4009 400 No withdrawal permission The API Key do not have withdrawal permission
-4010 400 Withdrawals on the same day exceed the maximum limit for a single day The withdrawal request exceeds the daily maximum limit
-4011 400 System error The system has an internal error. Please contact our API Team
-4012 400 Parameter error The parameter entered was invalid
-4013 400 Withdraw repeatedly The withdrawal has been submitted multiple times. Please wait and try again
-4014 400 The type of whitelist is invalid The type of whitelist is invalid
-4016 400 twoFaToken missing. Please send valid twoFaToken as 2FA is enabled for this action twoFaToken missing. Please send valid twoFaToken as 2FA is enabled for this action
-4017 400 twoFaToken wrong, please send valid twoFaToken twoFaToken wrong, please send valid twoFaToken
-4018 400 twoFaToken used before. Please wait and try again later twoFaToken used before. Please wait and try again later
-4019 400 The withdraw exceeded the predefined maximum limit, and has been rejected The withdraw exceeded the predefined maximum limit, and has been rejected
-4020 400 The withdrawal happened during abnormal operation hours, and had been rejected The withdrawal happened during abnormal operation hours, and had been rejected
-5000 400 Duplicate IN-KIND subscription order Duplicate IN-KIND subscription order
-5001 400 Fund code is invalid Fund code is invalid
-5002 400 Deposit address does not exist Deposit address does not exist
-5003 400 Invalid address. Please verify Invalid address. Please verify
-5004 400 Signature verification failed because the address had been whitelisted by another account. Signature verification failed because the address had been whitelisted by another account.
-5005 400 Signature verification fails because client submits incorrect signature result. Signature verification fails because client submits incorrect signature result.
-5006 400 Signature verification failed because the address had been whitelisted before. Signature verification failed because the address had been whitelisted before.
-5011 400 No Subscription found. No Subscription found.
-5012 400 Unknown subscriptionId Unknown subscriptionId
-5013 400 Subscription failed. Subscription failed.
-5021 400 Only one of 'buyAmount' or 'sellAmount' must be specified. Only one of 'buyAmount' or 'sellAmount' must be specified.
-5022 400 quoteId expired. Please get a quote again. quoteId expired. Please get a quote again.
-5023 400 Insufficient Fund Position. Insufficient Fund Position.
-5024 400 The amount is below the minimum required: 100 USD or equivalent USD. The amount is below the minimum required: 100 USD or equivalent USD.
-5025 400 Exceed the maximum buy amount. Exceed the maximum buy amount.
-5026 400 Unsupported Quote Pair. Unsupported Quote Pair.
-5027 400 Invalid orderId: %s provided. Invalid orderId: %s provided.
-5030 400 The Length of %s cannot exceed %s The Length of %s cannot exceed %s
-5031 400 Unsupported quote pair Unsupported quote pair
-5032 400 Precision illegal Precision illegal
-5033 400 Precision illegal Precision illegal
-5034 400 Fail to generate the clientOrderId Fail to generate the clientOrderId
-5035 400 %s %s
-5036 400 %s %s

Cancel Reject Reasons

Error Msg Error Msg ZH Memo
SYSTEM_CANCEL 系统撤单,默认 Default Error Message. Also include scenes: Solicited Cancellation by System or Operation Staff. 默认的拒绝错误文案,也包括系统自动执行的或运营人员执行的撤单操作。
USER_CANCEL 客户自主撤单 The customer initiates the order cancellation actively,客户主动发起的撤单
RISKLIMIT_CANCEL 风控撤单 Covers order cancellations caused by trading rule restrictions such as changes in risk preference levels,IOC 订单情况,流动性保护等导致的撤单
BLOCKED_CANCEL 账户禁用撤单 Cancellation due to the account being disabled,当账户被禁用时执行的撤单操作
CLOSED_CANCEL 交易所闭市撤单 Cancellation when the exchange closes urgently,交易所因紧急情况闭市时进行的撤单
OFFLINE_CANCEL 交易对下架撤单 Cancellation when the trading pair is delisted,交易对下架时进行的撤单操作
SELF_TRADE_CANCEL 自成交撤单 Cancellation to avoid self-trade,为避免自成交而进行的撤单

WEBSOCKET API

Access URL

Python Public Stream Sample

import hashlib
import hmac
import json
import time
import websocket
import logging
import threading

########################################################################################################################
# Test Websocket API 

# Copyright: Hashkey Trading 2023

########################################################################################################################

class WebSocketClient:
    def __init__(self):
        self._logger = logging.getLogger(__name__)
        self._ws = None
        self._ping_thread = None

    def _on_message(self, ws, message):
        self._logger.info(f"Received message: {message}")
        data = json.loads(message)
        if "pong" in data:
            # Received a pong message from the server
            self._logger.info("Received pong message")
        # Handle the received market data here

    def _on_error(self, ws, error):
        self._logger.error(f"WebSocket error: {error}")

    def _on_close(self, ws):
        self._logger.info("Connection closed")

    def _on_open(self, ws):
        self._logger.info("Subscribe topic")
        sub = {
            "symbol": "BTCUSD",
            "topic": "trade",
            "event": "sub",
            "params": {
                "binary": False
            },
            "id": 1
        }
        ws.send(json.dumps(sub))

        # Start the ping thread after connecting
        self._start_ping_thread()


    def _start_ping_thread(self):
        def send_ping():
            while self._ws:
                ping_message = {
                    "ping": int(time.time() * 1000)  # Send a timestamp as the ping message
                }
                self._ws.send(json.dumps(ping_message))
                self._logger.info(f"Send ping message: {ping_message}")
                time.sleep(5)

        self._ping_thread = threading.Thread(target=send_ping)
        self._ping_thread.daemon = True
        self._ping_thread.start()

    def unsubscribe(self):
        if self._ws:
            self._logger.info("Unsubscribe topic")
            unsub = {
                "symbol": "BTCUSD",
                "topic": "trade",
                "event": "cancel",
                "params": {
                    "binary": False
                },
                "id": 1
            }
            self._ws.send(json.dumps(unsub))

    def connect(self):
        base_url = 'wss://stream-pro.sim.hashkeydev.com'
        endpoint = 'quote/ws/v1'
        stream_url = f"{base_url}/{endpoint}"
        self._logger.info(stream_url)
        self._logger.info(f"Connecting to {stream_url}")

        self._ws = websocket.WebSocketApp(stream_url,
                                          on_message=self._on_message,
                                          on_error=self._on_error,
                                          on_close=self._on_close)
        self._ws.on_open = self._on_open

        self._ws.run_forever()

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)

    client = WebSocketClient()
    client.connect()

Python Private Stream Sample

import hashlib
import hmac
import json
import time
import websocket
import logging
import threading
import requests
import datetime

########################################################################################################################
# Test Websocket API 

# Copyright: Hashkey Trading 2023

########################################################################################################################

class WebSocketClient:
    def __init__(self, user_key, user_secret, subed_topic=None):
        if subed_topic is None:
            subed_topic = []
        self.user_key = user_key
        self.user_secret = user_secret
        self.subed_topic = subed_topic
        self.listen_key = None
        self._logger = logging.getLogger(__name__)
        self._ws = None
        self._ping_thread = None
        self.last_listen_key_extend = time.time()

    def generate_listen_key(self):
        params = {
            'timestamp': int(time.time() * 1000),
        }
        api_headers = {
            'X-HK-APIKEY': self.user_key,
            'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
        }
        signature = self.create_hmac256_signature(secret_key=self.user_secret, params=params)
        params.update({
            'signature': signature,
        })
        response = requests.post(url=f"/api/v1/userDataStream", headers=api_headers, data=params)
        data = response.json()
        if 'listenKey' in data:
            self.listen_key = data['listenKey']
            self._logger.info(f"Generated listen key: {self.listen_key}")
        else:
            raise Exception("Failed to generate listen key")

    def extend_listenKey_timeLimit(self):
        params = {
            'timestamp': int(time.time() * 1000),
            'listenKey': self.listen_key,
        }
        api_headers = {
            'X-HK-APIKEY': self.user_key,
            'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
        }
        signature = self.create_hmac256_signature(secret_key=self.user_secret, params=params)
        params.update({
            'signature': signature,
        })
        response = requests.put(url=f"/api/v1/userDataStream", headers=api_headers, data=params)
        if response.status_code == 200:
            self._logger.info("Successfully extended listen key validity.")
        else:
            self._logger.error("Failed to extend listen key validity.")

    def create_hmac256_signature(self, secret_key, params, data=""):
        for k, v in params.items():
            data = data + str(k) + "=" + str(v) + "&"
        signature = hmac.new(secret_key.encode(), data[:-1].encode(), digestmod=hashlib.sha256).hexdigest()
        return signature

    def _on_message(self, ws, message):
        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        self._logger.info(f"{current_time} - Received message: {message}")

        data = json.loads(message)
        if "pong" in data:
            self._logger.info("Received pong message")
        # Handle other messages here

    def _on_error(self, ws, error):
        self._logger.error(f"WebSocket error: {error}")

    def _on_close(self, ws):
        self._logger.info("Connection closed")

    def _on_open(self, ws):
        self._logger.info("Subscribing to topics")
        for topic in self.subed_topic:
            sub = {
                "symbol": "BTCUSD",
                "topic": topic,
                "event": "sub",
                "params": {
                    "limit": "100",
                    "binary": False
                },
                "id": 1
            }
            ws.send(json.dumps(sub))
        self._start_ping_thread()

    def _start_ping_thread(self):
        def send_ping():
            while self._ws:
                current_time = time.time()
                if current_time - self.last_listen_key_extend > 1800:  # Extend listen key every 30 minutes
                    self.extend_listenKey_timeLimit()
                    self.last_listen_key_extend = current_time

                ping_message = {"ping": int(time.time() * 1000)}
                self._ws.send(json.dumps(ping_message))
                self._logger.info(f"Sent ping message: {ping_message}")
                time.sleep(5)

        self._ping_thread = threading.Thread(target=send_ping)
        self._ping_thread.daemon = True
        self._ping_thread.start()

    def unsubscribe(self):
        if self._ws:
            self._logger.info("Unsubscribing from topics")
            for topic in self.subed_topic:
                unsub = {
                    "symbol": "BTCUSD",
                    "topic": topic,
                    "event": "cancel_all",
                    "params": {
                        "limit": "100",
                        "binary": False
                    },
                    "id": 1
                }
                self._ws.send(json.dumps(unsub))

    def connect(self):
        if not self.listen_key:
            self.generate_listen_key()

        base_url = 'wss://stream-pro.sim.hashkeydev.com'
        endpoint = f'api/v1/ws/{self.listen_key}'
        stream_url = f"{base_url}/{endpoint}"
        self._logger.info(f"Connecting to {stream_url}")

        self._ws = websocket.WebSocketApp(stream_url,
                                          on_message=self._on_message,
                                          on_error=self._on_error,
                                          on_close=self._on_close)
        self._ws.on_open = self._on_open

        self._ws.run_forever()

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    user_key = "YOUR_USER_KEY"
    user_secret = "YOUR_USER_SECRET"
    subed_topics = ["trade"]
    client = WebSocketClient(user_key, user_secret, subed_topics)
    client.connect()

Sandbox Environment

Production Environment

Note: Replace {listenKey} with your actual listen key obtained from the Obtain ListenKey.


For example in Postman, you can test our websocket in steps:

  1. Create a new request and select Websocket
  2. Input wss://stream-pro.sim.hashkeydev.com/quote/ws/v1 or wss://stream-pro.sim.hashkeydev.com/api/v1/ws/{listenKey} and click "Connect"

Heartbeat check

PublicStream Heartbeat

Ping message format is as follows:

// From Sent by the user
{
   "ping": 1748503859938
}

Pong message format is as follows:

// Public Stream, return server's timestamp
{
    "pong": 1748503865406
}

When a user's websocket client application successfully connects to HashKey websocket server, the client is recommended to initiate a periodic heartbeat message (ping message) every 10 seconds, which is used to keep alive the connection.

PrivateStream Heartbeat

// From Websocket Server
{
    "ping": 1748504490208,
    "channelId": "02ac86fffe5fdf52-00000001-00266eb0-74a37ad40fb20d81-0cda790b"
}

// Respond from client
{
    "pong": 1748504490208
}

Automatic disconnection mechanism (Only for Private Stream)

The websocket server will send a ping message every 30 seconds. We recommend clients respond with a pong message containing the same timestamp. It's not necessary to include the channelId. A mismatched pong timestamp will not affect the connection — we mainly care about receiving the pong itself, which indicates the connection is alive. (This mechanism is primarily used for internal latency calculation and statistics.) If the client has no heartbeat activity for 60 minutes, the session will be closed by the server.

Market Place Stream

Public Stream

Use Public stream V1

Request Example:

{
    "event": "SUBSCRIBE",
    "topic": "rfqs"
}

Subscription parameters:

Parameter Type Required Example value Description
event STRING Y SUBSCRIBE , UNSUBSCRIBE sub , cancel
topic STRING Y rfqs, quotes


topic=rfqs

  • Public channel, push all "new" RFQs

  • newly created rfqs or rfqs becomes "new" again (like accepted quote expired before confirmation, the rfq will become "new")

{
  "event": "rfqCreated",
  "topic": "rfqs",
  "data": {
      "rfqId": "RFQ_123",
      "buyCcy": "BTC",
      "sellCcy": "USDT",
      "buyAmount": "2",
      "sellAmount": "",
      "rfqMode": "real-time",
      "expire_time": 1717410000
  }
}

topic=quotes

  • Public channel, push all quotes once created
{
  "event": "quotesCreated",
  "topic": "quotes",
  "data": {
    "quoteId": "QUOTE_789456123",
    "rfqId": "RFQ638459562162049024",
    "buyCcy": "BTC",
    "sellCcy": "USDT",
    "buyAmount": "2",
    "sellAmount": "",
    "price": "68900",
    "expireTime": 1717394200
  }
}

WS Push Demo 👉

Private Stream

topic=bestQuote

  • Push the best quote portfolio to the channel (if at least 3 valid quotations are met within 3s, or all valid quotes after 3s)

  • Only list the latest quote from each LP

  • Ranking principle: rfqMode > Price > quote time

{
  "topic": "bestQuote",
  "data": [
        {
            "id": 9,
            "inquiryOrderId": "MP738048140639408128",  //rfqId
            "lpName": "WX",
            "quoteOrderId": "MPQ738048203885318144",   //quoteId
            "direction": 1,
            "status": 0,
            "buyAssetId": "BTC",
            "buyAmount": "0.0942",
            "sellAssetId": "USDT",
            "sellAmount": "10000",
            "price": "106050",
            "submitTime": 1753772404507,
            "dateExpiry": 1753772464507,
            "expirySeconds": 60,
            "remainingTime": 1122,
            "inquirySettleType": 2,
            "quoteSettleType": 1,    // 1: delayed   2: real-time
            "rank": 1,
            "isBestPrice": true,
            "isRecommendPrice": true
        },
        {
            "id": 10,
            "inquiryOrderId": "MP738048140639408128",   //rfqId
            "lpName": "GSR",
            "quoteOrderId": "MPQ738048203885318145",   //quoteId
            "direction": 1,
            "status": 0,
            "buyAssetId": "BTC",
            "buyAmount": "0.0942",
            "sellAssetId": "USDT",
            "sellAmount": "10000",
            "price": "106059",
            "submitTime": 1753772404507,
            "dateExpiry": 1753772464507,
            "expirySeconds": 60,
            "remainingTime": 1122,
            "inquirySettleType": 2,
            "quoteSettleType": 1,    // 1: delayed   2: real-time
            "rank": 2,
            "isBestPrice": false,
            "isRecommendPrice": false
        },
  ]
}

topic=rfqUpdates

{
  "event": "update",
  "topic": "rfqUpdates",
  "data": {
      "rfqId": "RFQ_123",
      "rfqClOrderId": "RFQClOrder_123",
      "buyCcy": "BTC",
      "sellCcy": "USDT",
      "buyAmount": "",
      "sellAmount": "2",
      "rfqMode": "real-time",
      "quoteId": "quote_123",
      "price": 120001,
      "quoteMode": "real-time",
      "status": "accepted",
      "statusInt": "2",
      "isLPReject": false,     
      "expiryTime": 1717410000 
  }
}

Use Private stream

Note: Replace {listenKey} with your actual listen key obtained from the Obtain ListenKey.


WS Push Demo 👉

English 繁體中文 Coming Soon