Skip to content

Latest commit

 

History

History
405 lines (288 loc) · 21.3 KB

api-doc.md

File metadata and controls

405 lines (288 loc) · 21.3 KB

Spot Exchange API

Logo

Flow of Contents

Introduction

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.

API keys

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.

My keys

Read and trade keys

Rate Limits

REST API

For authenticated calls, rate limits are per API method, per API key:

Method Limit

15 requests per 100ms each

  • private/create-order
  • private/cancel-order
  • private/cancel-all-orders
  • private/margin/create-order
  • private/margin/cancel-order
  • private/margin/cancel-all-orders

30 requests per 100ms

  • private/get-order-detail
  • private/margin/get-order-detail

1 requests per second

  • private/get-trades
  • private/margin/get-trades
  • private/get-order-history
  • private/margin/get-order-history

3 requests per 100ms each

  • All others

For public market data calls, rate limits are per API method, per IP address

100 requests per second each

  • public/get-book
  • public/get-ticker
  • public/get-trades

Websockets

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

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.

Endpoints

REST API Root

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}

Production

REST API v2 --> https://api.crypto.com/v2/{method}
REST API v1 --> https://api.crypto.com/v1/{method}

Websocket Root

The Websocket is available across two servers:

  • the User API Websocket (for authenticated requests and subscriptions)
  • Market Data Websocket:

UAT Sandbox

  • Websocket (User API and Subscriptions)
    wss://uat-stream.3ona.co/v2/user
  • Websocket (Market Data Subscriptions)
    wss://uat-stream.3ona.co/v2/market

Production

  • Websocket (User API and Subscriptions)
    wss://stream.crypto.com/v2/user
  • Websocket (Market Data Subscriptions)
    wss://stream.crypto.com/v2/market

Common API Reference

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.

Naming Conventions

  • All methods and URLs in dash-case
  • All parameters in snake_case
  • Enums in full uppercase and SNAKE_CASE

Request Format

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)

Response Format

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

Error Response Format

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.

Response Codes and Reason

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.

Websocket Termination Codes

Code Description
1000 Normal disconnection by server, usually when the heartbeat isn't handled properly
1006 Abnormal disconnection
1013 Server restarting -- try again later

Digital Signature - public/auth

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:

  1. If "params" exist in the request, sort the request parameter keys in ascending (alphabetical) order.
  2. Combine all the ordered parameter keys as key + value (no spaces, no delimiters). Let's call this the parameter string
  3. Next, do the following: method + id + api_key + parameter string + nonce
  4. Use HMAC-SHA256 to hash the above using the API Secret as the cryptographic key
  5. 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.

Example

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);

Issues

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:

  1. Don't allow whole number values to have decimals
  2. Ensure the payload casts number values properly before concatenating
  3. 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

Common methods

Websocket Heartbeats public/respond-heartbeat

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)

public/auth

Digital Signature

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.

Request Params

Name Type Description
api_key string API key
sig2 string Digital Signature

Applies To: Websocket (User API)

public/get-instruments

Provides information on all supported instruments (e.g. BTC_USDT)

For the websocket, as a public function, it can be called without authentication.

Applies To

  • REST (GET method)
  • Websocket (User API)

Response Attributes

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

Footnotes

  1. User Acceptance Testing

  2. signature