- Spot Exchange API
Welcome to my markdowned edition of the Crypto.com Exchange V2 API reference documentation.
The Crypto.com Exchange provides developers with a REST and websocket API.
The majority of API calls are available across both mediums in the same request and response formats, allowing smooth transition and a reduced learning curve between the two platforms.
Where applicable, all API calls come with detailed information on both the request and response parameters, all in a simple JSON format.
You can genrate API keys for the exchange only on desktop in your Crypto.com exchange account under User Center -> API. After generating the key, there are two things to carefully note down:
- API Key
- Secret Key
API Key and Secret are randomly generated by the system and can not be modified. Default settings will be set to "Can Read" only.
TODO: investigate other options of adding or removing certain permissions for your API Key via Web UI.
You can optionally specify a whitelist of IP addresses when generating the API Key. If specified, the API can only be used from the whitelisted IP addresses.
For authenticated calls, rate limits are per API method, per API key:
Method Limit
- private/create-order
- private/cancel-order
- private/cancel-all-orders
- private/margin/create-order
- private/margin/cancel-order
- private/margin/cancel-all-orders
- private/get-order-detail
- private/margin/get-order-detail
- private/get-trades
- private/margin/get-trades
- private/get-order-history
- private/margin/get-order-history
- All others
- public/get-book
- public/get-ticker
- public/get-trades
Websocket | Limit |
---|---|
User API | 150 requests per second |
Market Data | 100 requests per second |
private/get-trades and private/get-order-history | 5 requests per second on the Websocket |
We recommend adding a 1-second sleep after establishing the websocket connection, and before requests are sent. This will avoid occurrences of
rate-limit (TOO_MANY_REQUESTS
) errors, as the websocket rate limits are pro-rated based on the calendar-second that the websocket connection was
opened.
REST API v1 and v2 have separate endpoints.
Future versions will share the same endpoint as v2, but with the version incremented.
Note: REST API V2 requests need to be sent as "Content Type: application/json"
UAT 1 - Sandbox
REST API v2 --> https://uat-api.3ona.co/v2/{method}
REST API v1 --> https://uat-api.3ona.co/v1/{method}
REST API v2 --> https://api.crypto.com/v2/{method}
REST API v1 --> https://api.crypto.com/v1/{method}
The Websocket is available across two servers:
- the User API Websocket (for authenticated requests and subscriptions)
- Market Data Websocket:
- Websocket (User API and Subscriptions)
wss://uat-stream.3ona.co/v2/user - Websocket (Market Data Subscriptions)
wss://uat-stream.3ona.co/v2/market
- Websocket (User API and Subscriptions)
wss://stream.crypto.com/v2/user - Websocket (Market Data Subscriptions)
wss://stream.crypto.com/v2/market
Most of the APIs for REST and Websockets are shared, and follow the same request format and response, allowing users to easily switch between the two methods.
The Applies To section under each API allows you to see which platform supports the API.
- All methods and URLs in
dash-case
- All parameters in
snake_case
- Enums in full uppercase and
SNAKE_CASE
The following information applies to both REST API and websockets commands:
Name | Type | Required | Description |
---|---|---|---|
id | long | N | Request Identifier, Range: 0 to 9,223,372,036,854,775,807, Response message will contain the same id |
method | string | Y | The method to be invoked |
params | object | N | Parameters for the methods |
api_key | string | Depends | API key see Digital signature |
nonce | long | Y | Current timestamp (milliseconds since the Unix epoch) |
Name | Type | Description |
---|---|---|
id | long | Original request identifier |
method | string | Method invoked |
result | object | Result object |
code | int | 0 for success, see below for full list |
message | string | (optional) For server or error messages |
original | string | (optional) Original request as a string, for error cases |
Due to the asynchronous nature of websocket requests, a robust and consistent error response is crucial in order to match the response with the request.
To ensure API consistency for websocket error responses, if the id and method is omitted in the original request, id will have a value of -1 and method will have a value of ERROR.
The original request will be returned as an escaped string in the original field.
These codes are shared by both the response, and the reason field for rejected orders.
Code | HTTP | Status Message | Code Description |
---|---|---|---|
0 | 200 | ------------------------------- | Success |
10000 | 200 | PARTIAL_SUCCESS | Batch request processed successfully and some requests succeeded (E.g. Some orders created when creating a list of orders) |
10001 | 500 | SYS_ERROR | Malformed request, (E.g. not using application/json for REST) |
10002 | 401 | UNAUTHORIZED | Not authenticated, or key/signature incorrect |
10003 | 401 | IP_ILLEGAL IP | address not whitelisted |
10004 | 400 | BAD_REQUEST | Missing required fields |
10005 | 401 | USER_TIER_INVALID | Disallowed based on user tier |
10006 | 429 | TOO_MANY_REQUESTS | Requests have exceeded rate limits |
10007 | 400 | INVALID_NONCE | Nonce value differs by more than 30 seconds from server |
10008 | 400 | METHOD_NOT_FOUND | Invalid method specified |
10009 | 400 | INVALID_DATE_RANGE | Invalid date range |
10010 | 200 | FAIL | Batch request processed successfully but all requests failed (E.g. No orders created when creating a list of orders) |
20001 | 400 | DUPLICATE_RECORD | Duplicated record |
20002 | 400 | NEGATIVE_BALANCE | Insufficient balance |
30003 | 400 | SYMBOL_NOT_FOUND | Invalid instrument_name specified |
30004 | 400 | SIDE_NOT_SUPPORTED | Invalid side specified |
30005 | 400 | ORDERTYPE_NOT_SUPPORTED | Invalid type specified |
30006 | 400 | MIN_PRICE_VIOLATED | Price is lower than the minimum |
30007 | 400 | MAX_PRICE_VIOLATED | Price is higher than the maximum |
30008 | 400 | MIN_QUANTITY_VIOLATED | Quantity is lower than the minimum |
30009 | 400 | MAX_QUANTITY_VIOLATED | Quantity is higher than the maximum |
30010 | 400 | MISSING_ARGUMENT | Required argument is blank or missing |
30013 | 400 | INVALID_PRICE_PRECISION | Too many decimal places for Price |
30014 | 400 | INVALID_QUANTITY_PRECISION | Too many decimal places for Quantity |
30016 | 400 | MIN_NOTIONAL_VIOLATED | The notional amount is less than the minimum |
30017 | 400 | MAX_NOTIONAL_VIOLATED | The notional amount exceeds the maximum |
30023 | 400 | MIN_AMOUNT_VIOLATED | Amount is lower than the minimum |
30024 | 400 | MAX_AMOUNT_VIOLATED | Amount is higher than the maximum |
30025 | 400 | AMOUNT_PRECISION_OVERFLOW | Amount precision exceeds the maximum |
40001 | 400 | MG_INVALID_ACCOUNT_STATUS | Operation has failed due to your account's status. Please try again later. |
40002 | 400 | MG_TRANSFER_ACTIVE_LOAN | Transfer has failed due to holding an active loan. Please repay your loan and try again later. |
40003 | 400 | MG_INVALID_LOAN_CURRENCY | Currency is not same as loan currency of active loan |
40004 | 400 | MG_INVALID_REPAY_AMOUNT | Only supporting full repayment of all margin loans |
40005 | 400 | MG_NO_ACTIVE_LOAN | No active loan |
40006 | 400 | MG_BLOCKED_BORROW | Borrow has been suspended. Please try again later. |
40007 | 400 | MG_BLOCKED_NEW_ORDER | Placing new order has been suspended. Please try again later. |
50001 | 400 | DW_CREDIT_LINE_NOT_MAINTAINED | Please ensure your credit line is maintained and try again later. |
Code | Description |
---|---|
1000 | Normal disconnection by server, usually when the heartbeat isn't handled properly |
1006 | Abnormal disconnection |
1013 | Server restarting -- try again later |
For REST API, only the private methods require a Digital Signature (as "sig") and API key (as "api_key") to be passed in. These private endpoints are only accessible by authenticated users.
For Websocket (User API), the public/auth command has to be invoked ONCE per session, with the Digital Signature (as "sig") and API key (as "api_key") as part of the request. Once authenticated, you will gain access to user-specific commands, and no longer need to use the pass in the Digital Signature and API key anymore for the duration of the session.
The authentication is based on the pairing of the API Key, along with the HMAC-SHA256 hash of the request parameters using the API Secret as the cryptographic key.
You should NEVER explicitly include the API Secret Key in plain-text in your request.
The algorithm for generating the HMAC-SHA256 signature is as follows:
- If "params" exist in the request, sort the request parameter keys in ascending (alphabetical) order.
- Combine all the ordered parameter keys as key + value (no spaces, no delimiters). Let's call this the parameter string
- Next, do the following: method + id + api_key + parameter string + nonce
- Use HMAC-SHA256 to hash the above using the API Secret as the cryptographic key
- Encode the output as a hex string -- this is your Digital Signature
Since all parameters for calculating the HMAC-SHA256 hash are present in the request except the API Secret, the server-side will independently calculate the Digital Signature as well, and if done correctly, the computed hashes will match.
const crypto = require("crypto-js");
const signRequest = (request_body, api_key, secret) => {
const { id, method, params, nonce } = request_body;
/**preamlbe to order params in ascending (alphabetical) order**/
function isObject(obj) { return obj !== undefined && obj !== null && obj.constructor == Object; }
function isArray(obj) { return obj !== undefined && obj !== null && obj.constructor == Array; }
function arrayToString(obj) { return obj.reduce((a,b) => { return a + (isObject(b) ? objectToString(b) : (isArray(b) ? arrayToString(b) : b)); }, ""); }
/**sort params**/
function objectToString(obj) { return (obj == null ? "" : Object.keys(obj).sort().reduce((a, b) => { return a + b + (isArray(obj[b]) ? arrayToString(obj[b]) : (isObject(obj[b]) ? objectToString(obj[b]) : obj[b])); }, "")); }
const paramsString = objectToString(params);
console.log(paramsString);
const sigPayload = method + id + api_key + paramsString + nonce;
/**encode request string with crypto[graphic] key's hex value**/
request_body.sig = crypto.HmacSHA256(sigPayload, secret).toString(crypto.enc.Hex);
return request_body;
};
const apiKey = "token"; /* User API Key */
const apiSecret = "secretKey"; /* User API Secret */
let request = {
id: 11,
//recall: Basics -> Requests
method: "private/get-order-detail",
api_key: API_KEY,
params: {
order_id: 53287421324
},
nonce: 1587846358253,
};
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
console.log(requestBody);
Based on the language, and the way data-types are handled, the digital signature may be incorrectly calculated for certain values.
One known case is if parameters contain numbers, and the value passed in is a whole numbers that still has decimal suffixes, e.g. 8000.000 instead of 8000.
When the JSON request is sent to the server, the client (when parsing as JSON) may cast the number 8000.000 as 8000 automatically, which is what the server would see.
However, the digital signature may have been calculated using 8000.000 in the payload, which would result in a digital signature mismatch.
If this scenario happens in your case, there are three options:
- Don't allow whole number values to have decimals
- Ensure the payload casts number values properly before concatenating
- Wrap the values in quotation marks to make them strings -- this is allowed by the server even if the parameter is marked as a number data type
For websocket connections, the system will send a heartbeat message to the client every 30 seconds.
The client must respond back with the public/respond-heartbeat
method, using the same matching id, within 5 seconds, or the connection will break.
Request Params - None
Applies To Websocket (User API), Websocket (Market Data Subscriptions)
REST API calls do NOT need to do this.
Important Note:
We recommend adding a 1-second sleep after establishing the websocket connection, and before requests are sent. This will avoid occurrences of
rate-limit (TOO_MANY_REQUESTS
) errors, as the websocket rate limits are pro-rated based on the calendar-second that the websocket connection was
opened.
Name | Type | Description |
---|---|---|
api_key | string | API key |
sig2 | string | Digital Signature |
Applies To: Websocket (User API)
Provides information on all supported instruments (e.g. BTC_USDT)
For the websocket, as a public function, it can be called without authentication.
- REST (GET method)
- Websocket (User API)
An array of instruments, consisting of:
Name | Type | Description |
---|---|---|
instrument_name | string | e.g. BTC_USDT |
quote_currency | string | e.g. USDT |
base_currency | string | e.g. BTC |
price_decimals | integer | Maximum decimal places for specifying price |
quantity_decimals | integer | Maximum decimal places for specifying quantity |
margin_trading_enabled | boolean | true or false |