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
Restful URL:
https://api-pro.sim.hashkeydev.comWebSocket:
wss://stream-pro.sim.hashkeydev.comWebsite: https://global.sim.hashkeydev.com/sg
Production Environment
Restful URL:
https://api-pro.hashkey.comWebSocket:
wss://stream-pro.hashkey.comWebsite: https://global.hashkey.com/sg
General API Information
All responses will return a JSON object or array.
Data is returned in ascending order with the earlier data displayed first and subsequent updates appearing later
All time or timestamp-related variables are measured in milliseconds (ms)
HTTP 4XXerror code indicate that the request content is invalid. This typically originates from the client's end.HTTP 429error code indicates that the request rate limit has been exceeded.HTTP 418error code when our server have detected the IP address continues to send subsequent requests after receiving429error code and is automatically blockedHTTP 5XXindicates an internal system error. This signifies that the issue originates within the trading system. When addressing this error, it's important not to immediately categorise it as a failed task. The execution status is uncertain, it could potentially be either successful or unsuccessful.For GET endpoints, parameters must be sent as query strings.
For POST, PUT, and DELETE endpoints, unless explicitly stated otherwise, parameters must be sent as query strings or in the request body with the content type set to
application/x-www-form-urlencoded.Request Parameters can be sent in any order.
If there are parameters in both query string and request body, only the parameters of query string will be used.
Access Restrictions
If any rate limit is violated, a
429error code will be returnedEach API endpoint has an associated with a specific weight, and certain endpoints may possess varying weights based on different parameters. Endpoints that consume more resources will have a higher weight assigned to them.
Upon receiving
429error code, please take precautionary steps to cease sending requests. API abuse is strictly prohibitedIt is recommended to use Websocket API to obtain corresponding real-time data as much as possible to reduce the traffic of access restrictions caused by frequent API requests.
Order Rate Limiting
Unless explicitly stated otherwise, each API Key has a default rate limit of 2 requests per second for query-related endpoints, while order-related endpoints allow 10 requests per second.
When the number of orders exceeds the set limit, a response with an HTTP CODE 429 will be received. Please wait 1 minute for the suspended period to expire.
Endpoint Security Types
Each endpoint is assigned a security type that determines how you interact with it.
The API-KEY must be passed in the REST API header as X-APIKEY.
API-KEY and SECRET-KEY are case-sensitive.
By default, API-KEY have access to all secure endpoints.
API-KEY Management
Users have to log in the exchange website and apply for an API-KEY, please make sure to remember the following information when creating an API key:
- Access key: API access key
- Secret key: The key used for signature authentication encryption (visible to the application only)
Users have to assign permissions to API-KEY. There are two kinds of permissions,
- READ: read permission is used for data query interfaces such as order query, transaction query, etc.
- TRADE: read-write permission is used for order placing, order cancelling, including transfer permission whereby user can transfer between subaccounts under the same main trading account
Both private REST and WebSocket modes require users to authenticate the transaction through the API-KEY passed in the API header. Refer to the following Authentication chapter for the signature algorithm of the API-KEY.
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
The SIGNED (signature required) endpoint needs to send a parameter, signature, in the query string or request body.
The endpoint is signed with HMAC SHA256. The HMAC SHA256 signature is the result of HMAC SHA256 encryption of the key. Use your secretKey as the key and totalParams as the value to complete this encryption process.
Signature is not case sensitive.
totalParams refers to concatenation of the query string and the request body.
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
- For a SIGNED endpoint, an additional parameter "timestamp" needs to be included in the request. This timestamp is in milliseconds and reflect the time when the request was intitated
- An optional parameter (not mandatory) recvWindow can be used to specify the validity period of the request in milliseconds. If recvWindow is not sent as part of the request, the default value is 5000
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
- queryString:
symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000
- HMAC SHA256 signature:
echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"
Shell standard output:
5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6
- curl command:
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×tamp=1538323200000&signature=5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6'
Example 2: In the request body
- requestBody:
symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000
- HMAC SHA256 signature:
echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"
Shell standard output:
5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6
- curl command:
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×tamp=1538323200000&signature=5f2750ad7589d1d40757a55342e621a44037dad23b5128cc70e18ec1d1c3f4c6'
Example 3: mixing queryString and request body
- queryString:
symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTC
- requestBody:
quantity=1&price=0.1&recvWindow=5000×tamp=1538323200000
- HMAC SHA256 signature:
echo -n "symbol=ETHBTC&side=BUY&type=LIMIT&timeInForce=GTCquantity=1&price=0.1&recvWindow=5000×tamp=1538323200000" | openssl dgst -sha256 -hmac "lH3ELTNiFxCQTmi9pPcWWikhsjO04Yoqw3euoHUuOLC3GYBW64ZqzQsiOEHXQS76"
Shell standard output:
885c9e3dd89ccd13408b25e6d54c2330703759d7494bea6dd5a3d1fd16ba3afa
- curl command:
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×tamp=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 AccountSub 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
- For the same coin & chainType & walletId, if the request parameter "quantity" is specified as the same value, the deposit random amount (Micropayment) will always remain the same.
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
- Start a new user data stream.
- The stream will close after 60 minutes unless a keepalive is sent.
- Recommended to send a reset request every 30 minutes. Reset-Listen-Key
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
- MarketData public stream V1:
wss://stream-pro.sim.hashkeydev.com/quote/ws/v1 - MarketData public stream V2:
wss://stream-pro.sim.hashkeydev.com/quote/ws/v2 - MarketPlace public stream:
wss://stream-pro.sim.hashkeydev.com/mp/ws/v1 - Private stream:
wss://stream-pro.sim.hashkeydev.com/api/v1/ws/{listenKey}
Production Environment
- MarketData public stream V1:
wss://stream-pro.hashkey.com/quote/ws/v1 - MarketData public stream V2:
wss://stream-pro.hashkey.com/quote/ws/v2 - MarketPlace public stream:
wss://stream-pro.hashkey.com/mp/ws/v1 - Private stream:
wss://stream-pro.hashkey.com/api/v1/ws/{listenKey}
Note: Replace {listenKey} with your actual listen key obtained from the Obtain ListenKey.
For example in Postman, you can test our websocket in steps:
- Create a new request and select Websocket

- Input
wss://stream-pro.sim.hashkeydev.com/quote/ws/v1orwss://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
- Sandbox:
wss://stream-pro.sim.hashkeydev.com/mp/ws/v1 - Production:
wss://stream-pro.hashkey.com/mp/ws/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
- Sandbox:
wss://stream-pro.sim.hashkeydev.com/api/v1/ws/{listenKey} - Production:
wss://stream-pro.hashkey.com/api/v1/ws/{listenKey}
Note: Replace {listenKey} with your actual listen key obtained from the Obtain ListenKey.
WS Push Demo 👉