# Crypto.com Exchange API v1 Documentation
> Fast, Reliable, and Secure Trading API
This file contains all documentation content in a single document following the llmstxt.org standard.
## Exchange FIX Protocol
Version: 1.0.0
Exchange FIX Protocol
## Introduction
Welcome to the Crypto.com Exchange FIX API reference documentation.
FIX (Financial Information eXchange) is a standard electronic messaging protocol which can be used to place orders, receive order updates and executions, and cancel orders. Our FIX API is based on the FIX 4.4 specification and modeled after FIX implementations of other popular cryptocurrency exchanges.
The FIX API is available across 3 servers: the user data server (order management), user data server (drop copy), and the market data server.
Users who are less familiar with FIX can also consider using the [REST API](/docs/api/rest-introduction) or [WebSocket API](/docs/api/websocket-introduction).
## Change Log
- **2025-08-29** - Update description on tag6616, tag10060, tag60 and tag52
- **2025-11-13** - Update 35=D, added tag20100 ReceiveWindow
- **2025-07-30** - Update 35=H, not available for Drop Copy session
- **2025-07-09** - Update 35=D, tag18=8 SMART_POST_ONLY
- **2025-06-26** - Added 35=G for OrderCancelReplaceRequest
- **2025-05-29** - Update 35=V, tag MarketDepth(264) include market depth 1
- **2025-04-23** - Update FIX housekeeping period date
- **2025-02-06** - Added tag 10060 into tag 35=8
- **2024-10-25** - Added tag 20101 and tag 20102 into tag 35=8
- **2024-09-26** - Added tag 880 TrdMatchID into tag 35=8
- **2024-09-10** - FIX 3.0 initial
- **2024-06-28** - Added Self Trade Prevention (STP) feature
- **2023-10-03** - Added tag544=2 for margin trading in 35=D
- **2023-04-25** - Added 35=W for market data
- **2023-04-17** - Update 35=D, update tag1107 remove '=I', '=M'
- **2023-04-17** - Updated details on 35=X, NoMDEntries(268)
- **2023-02-23** - Add wait interval in 35=A
- **2023-02-06** - Added tag 278 include details with order books
- **2023-02-02** - MDS 2.0 initial
- **2023-02-01** - Added tag18 in execution report
- **2022-12-02** - Update on tag 35=2
- **2022-12-01** - Update description on tag 20001
- **2022-11-22** - Update the default COMPIDs
- **2022-11-18** - Included the response and reason codes
- **2022-11-14** - Update tag 1107 TriggerPriceType description
- **2022-10-18** - Updated cancellation request tag 35=F
- **2022-09-08** - Updated logon requests
- **2022-06-30** - Updated mass order request
- **2022-03-21** - Initial v3 API
## Generating the API Key
Before sending any requests, you'll need to generate a new API key.
This can be done in the Exchange website under **User Center > API**.
After generating the key, there are two things you need to carefully note down:
- **API Key**
- **Secret Key**
API Key and Secret are randomly generated by the system and cannot be modified. Default settings will be set to "Can Read" only, and you have the option 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.
## Rate Limits
| FIX Endpoint | Limit |
|--------------|-------|
| Order Entry | 2500 requests per second |
| Market Data | 20 requests per second |
**Important Note:** We recommend adding a 1-second sleep after establishing the FIX connection, and before requests are sent. This will avoid occurrences of rate-limit errors, as the rate limits are pro-rated based on the calendar-second that the connection was opened.
## FIX Dictionary
Our FIX API implementation is based on the FIX Protocol 4.4 specifications, and on top of it we also include some tags from other versions of the FIX Specification, as well as some User Defined Fields.
We provide a custom dictionary in the QuickFIX XML format, which is also compatible with various FIX engine implementations.
## FIX Endpoints
To establish a FIX session, FIX clients must setup/use the AWS private link connection.
### UAT Sandbox
| FIX Gateway | FIX Endpoint | Sender Comp ID | Target Comp ID |
|-------------|--------------|----------------|----------------|
| User Data (Order Management) | tcp://uat1-fix-ud-f18a.crypto.local:31301 | UAT1.CLIENT_NAME.UD.00 | UAT1.CDC.UD |
| User Data (Drop Copy) | tcp://uat1-fix-uc-f18a.crypto.local:30300 | UAT1.CLIENT_NAME.UC.00 | UAT1.CDC.DC |
| Market Data (BTC related) | tcp://uat1-fix-md-f18a.crypto.local:34402 | UAT1.CLIENT_NAME_BTC.MD.00 | UAT1.CDC.MD |
| Market Data (ETH related) | tcp://uat1-fix-md-f18a.crypto.local:34403 | UAT1.CLIENT_NAME_ETH.MD.00 | UAT1.CDC.MD |
| Market Data (OTHERS related) | tcp://uat1-fix-md-f18a.crypto.local:3440[5-7] | UAT1.CLIENT_NAME_OTHERS.MD.00 | UAT1.CDC.MD |
### Production
| FIX Gateway | FIX Endpoint | Sender Comp ID | Target Comp ID |
|-------------|--------------|----------------|----------------|
| User Data (Order Management) | tcp://prd3-fix-ud-f18b.crypto.local:31301 | PRD3.CLIENT_NAME.UD.00 | PRD3.CDC.UD |
| User Data (Drop Copy) | tcp://prd3-fix-uc-f18b.crypto.local:30300 | PRD3.CLIENT_NAME.UC.00 | PRD3.CDC.UC |
| Market Data (BTC related) | tcp://prd3-fix-md-f18b.crypto.local:34402 | PRD3.CLIENT_NAME_BTC.MD.00 | PRD3.CDC.MD |
| Market Data (ETH related) | tcp://prd3-fix-md-f18b.crypto.local:34403 | PRD3.CLIENT_NAME_ETH.MD.00 | PRD3.CDC.MD |
| Market Data (OTHERS related) | tcp://prd3-fix-md-f18b.crypto.local:3440[5-7] | PRD3.CLIENT_NAME_OTHERS.MD.00 | PRD3.CDC.MD |
### Market Data Port Assignment
- **BTC related pairs** - Port 34402 (Note: ETH/BTC is NOT included on this instance)
- **ETH related pairs** - Port 34403 (Note: ETH/BTC is included on this instance)
- **Others** - Port 34405 [0-9A-D], Port 34406 [E-M], Port 34407 [N-Z]
## Standard Header and Trailer
This documentation uses `|` to represent the FIX field separator (byte 0x01). It should be replaced by 0x01 in actual messages.
### Standard Header
The header identifies the message type, length, destination, sequence number, origination point and time.
| Tag | Name | Type | Required | Description |
|-----|------|------|----------|-------------|
| 8 | BeginString | string | Y | Must be "FIX.4.4" |
| 9 | BodyLength | number | Y | Length of the message body in bytes |
| 35 | MsgType | string | Y | Message Type |
| 34 | MsgSeqNum | number | Y | Integer message sequence number |
| 43 | PossDupFlag | boolean | N | Indicates possible retransmission of message with this sequence number |
| 49 | SenderCompID | string | Y | See FIX Endpoints for details |
| 56 | TargetCompID | string | Y | See FIX Endpoints for details |
| 52 | SendingTime | UTCTimestamp | Y | Time when the message is being sent out from FIX Gateway |
| 97 | PossResend | boolean | N | Indicates that message may contain information sent under another sequence number |
**Processing PossDupFlag and PossResend:**
- **PossDupFlag (43=Y)** — if a message with this sequence number has been previously received, ignore message; if not, process normally.
- **PossResend (97=Y)** — forward message to application and determine if previously received (i.e. verify order id and parameters).
### Standard Trailer
Each FIX message is terminated by a Standard Trailer as a message delimiter as well as containing the checksum value.
| Tag | Name | Type | Required | Description |
|-----|------|------|----------|-------------|
| 10 | CheckSum | string | Y | Three bytes, simple checksum. Always last field in message |
---
## BusinessMessageReject (35=j)
BusinessMessageReject (35=j) The Business Message Reject message can reject an application-level message which fulfills session-level rules and cannot be rejected via any other means.
---
## FIX Drop Copy
Drop Copy flow for receiving real-time copies of all execution reports for trade monitoring and reconciliation.
Drop Copy provides a separate connection that mirrors execution reports from the Order Management flow, enabling:
- **Trade Monitoring**: Real-time visibility into all order activity and fills
- **Reconciliation**: Independent feed for back-office systems to verify trades
- **Audit Trail**: Complete record of all execution events
This flow receives:
- **Execution Reports** (35=8): All order status changes, fills, and confirmations
- **Cancel Rejects** (35=9): Notifications when cancel requests are rejected
## Important Notes
- Drop Copy is **read-only** — you cannot send orders or cancellations on this connection
- Use Drop Copy alongside Order Management for complete trade visibility
## Related Documentation
- [FIX Introduction](exchange-fix-protocol.info.mdx) — API overview, authentication, endpoints, and message structure
- [FIX Session Management](fix-session-management.tag.mdx) — Session management, logon/logout, and heartbeat messages
---
## ExecutionReport (35=8)
ExecutionReport (35=8) The ExecType (150) field indicates the reason why this ExecutionReport was sent.
**ExecType values:**
| ExecType | Description |
|----------|-------------|
| 0 | New order |
| 4 | Order cancelled |
| A | Response to a successful NewOrderSingle (D) request |
| 8 | Response to a rejected NewOrderSingle (D) request |
| 6 | Response to a successful OrderCancelRequest (F) request |
| I | Response to a OrderStatusRequest (H) |
| F | Trade |
---
## Heartbeat (35=0)
Heartbeat (35=0) The Heartbeat (0) monitors the status of the communication link and identifies when the last of a string of messages was not received.
* When either end of a FIX connection has not sent any data for HeartBtInt (108) seconds, it will transmit a Heartbeat (0) message.
* When either end of the connection has not received any data for (HeartBtInt (108) + "some reasonable transmission time") seconds, it will transmit a Test Request (1) message.
* If there is still no Heartbeat (0) message received after (HeartBtInt (108) + "some reasonable transmission time") seconds then the connection should be considered lost and corrective action be initiated.
* If HeartBtInt (108) is set to zero then no regular heartbeat messages will be generated. Note that a test request message can still be sent independent of the value of the HeartBtInt (108), which will force a Heartbeat (0) message.
* Heartbeats issued as the result of Test Request (1) must contain the TestReqID (112) transmitted in the Test Request (1) message. This is useful to verify that the Heartbeat (0) is the result of the Test Request (1) and not as the result of a regular timeout.
## Request
---
## EXCHANGE FIX Protocol(Fix)
Redirecting to [EXCHANGE FIX Protocol](./exchange-fix-protocol)...
---
## Logon (35=A)
Logon (35=A) Initiate FIX session with authentication credentials.
## FIX Digital Signature
For FIX API, the Logon (35=A) message has to be invoked ONCE per session, with the Digital Signature as Password (554) and API key as UserName (553) to be part of the message. Once authenticated, you will gain access to a FIX session, 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. Concatenate based on flow type:
- **(Case i. Order Management Flow)** `"public/auth" + MsgSeqNum (34) + api_key + "system_labelONEEX" + RawData (96)`
- **(Case ii. Market Data Flow)** `"public/auth" + MsgSeqNum (34) + api_key + RawData (96)`
- **(Case iii. Drop Copy Flow)** `"public/auth" + MsgSeqNum (34) + api_key + "system_labelONEEX" + RawData (96)`
2. Use HMAC-SHA256 to hash the above using the API Secret as the cryptographic key
3. Encode the output as a hex string -- this is your Digital Signature
The above method is similar to sign a Digital Signature for REST / WS, with the following equivalent field mappings:
| FIX Tag | Equivalent WS / REST Field for Signing Digital Signature |
|---------|----------------------------------------------------------|
| MsgType (35) | method |
| MsgSeqNum (34) | id |
| UserName (553) | api_key |
| RawData (96) | nonce in milliseconds |
| Password (554) | sig |
Please refer to the respective section to sign a Digital Signature for REST / WS for sample code.
## Remarks
We recommend adding 50 ms wait interval after receiving 35=A on both side, before sending first request.
The FIX gateway maintenance (Order Management flow only) will be carried out on second Thursday 07:05-07:15 (UTC) monthly. Please disconnect on 07:04 (UTC) and reconnect on 07:15 (UTC) with sequence number 1/1.
**Other options for client preferences:**
**Option 1:** Sequence number resets require by clients to LOGOFF and then LOGIN again using the Logon [A] message with the ResetSeqNumFlag (141) set to 'Y'. This resets the sequence numbers on both sides. Clients are free to perform this action whenever is convenient for their own schedule and set-up.
**Option 2:** Crypto.com FIX connections shall establish a cap to prevent sequence number counter overflow; Our FIX engine shall trigger disconnection and reset the sequence number to 1/1, either the inbound or outbound sequence number reach 2,147,480,000
## Request
---
## Logout (35=5)
Logout (35=5) The Logout (35=5) message initiates or confirms the termination of a FIX session. Disconnection without the exchange of Logout (35=5) messages should be interpreted as an abnormal condition.
Before actually closing the session, the logout initiator should wait for the opposite side to respond with a confirming Logout (35=5) message. This gives the remote end a chance to perform any Gap Fill operations that may be necessary. The session may be terminated if the remote side does not respond in an appropriate timeframe.
After sending the Logout (35=5) message, the logout initiator should not send any messages unless requested to do so by the logout acceptor via a ResendRequest (35=2).
SessionStatus values:
- 0 = session active
- 4 = Session logout complete
- 5 = Invalid username or password
- 6 = Account locked
- 7 = Logons are not allowed at this time
## Request
---
## MarketDataIncrementalRefresh (35=X)
MarketDataIncrementalRefresh (35=X) Response for Market Data Request.
---
## MarketDataRequestReject (35=Y)
MarketDataRequestReject (35=Y) The Market Data Request Reject is used when the broker cannot honor the Market Data Request (35=V), due to business or technical reasons. Brokers may choose to limit various parameters, such as the size of requests, whether just the top of book or the entire book may be displayed, and whether Full or Incremental updates must be used.
---
## MarketDataRequest (35=V)
MarketDataRequest (35=V) Subscribes to Market Data: Order Book, Trades.
Use MDReqID format: `book..` or `trade.`
**Response Attributes:**
See MarketDataIncrementalRefresh (35=X) and MarketDataRequestReject (35=Y) for details.
## Request
---
## Snapshot/Full Refresh (35=W)
Snapshot/Full Refresh (35=W) The Market Data messages are used as the response to a Market Data Request (V) message. In all cases, one Market Data message refers only to one Market Data Request (V). It can be used to transmit a 2-sided book of orders or list of quotes, a list of trades, index values, opening, closing, settlement, high, low, or VWAP prices, the trade volume or open interest for a security, or any combination of these.
---
## FIX Market Data
Market Data flow for receiving real-time market information via FIX protocol.
This flow supports:
- **Subscriptions**: Subscribe to market data channels (35=V MarketDataRequest)
- **Order Book Updates**: Receive incremental order book changes (35=X MarketDataIncrementalRefresh) and full snapshots (35=W MarketDataSnapshotFullRefresh)
- **Instrument Data**: Query available instruments (35=x SecurityListRequest, 35=c SecurityDefinitionRequest)
- **Rejections**: Handle subscription rejections (35=Y MarketDataRequestReject)
## Related Documentation
- [FIX Introduction](exchange-fix-protocol.info.mdx) — API overview, authentication, endpoints, and message structure
- [FIX Session Management](fix-session-management.tag.mdx) — Session management, logon/logout, and heartbeat messages
---
## MassOrder (35=DJ)
MassOrder (35=DJ) The MassOrder message, which we adopted from FIX 5.0 SP2, can be used to add or cancel multiple unrelated orders with a single message. Only the key order attributes for high performance trading are available.
The behaviour of individual orders within a MassOrder (35=DJ) may vary depending upon its attributes, e.g. OrdType (40) and TimeInForce (59). Individual orders may be cancelled with single order messages such as OrderCancelRequest. Each of the orders in the MassOrder (35=DJ) are to be treated as stand-alone individual orders.
**Response Attributes:**
MassOrder sends 35=D or 35=F in batch respectively. Each order will follow their respective execution report. See ExecutionReport for details.
## Request
---
## NewOrderSingle (35=D)
NewOrderSingle (35=D) Creates a new BUY or SELL order on the Exchange.
This call is asynchronous, so the response with Pending New is simply an acceptance of the request, but not necessarily mean it is confirmed into order book.
The drop copy subscription can be used to check when the order is successfully created.
See FIX Spot Order Life Cycle and ExecutionReport for details.
**Mandatory parameters based on OrdType:**
| OrdType | Side | Additional Mandatory Parameters |
|---------|------|--------------------------------|
| 1: MARKET | 1: BUY | CashOrderQty or OrderQty, mutually exclusive |
| 1: MARKET | 2: SELL | OrderQty |
| 2: LIMIT | 1: BUY | OrderQty, Price |
| 2: LIMIT | 2: SELL | OrderQty, Price |
**Response Attributes:**
* MsgType (35) = 8
* OrderID (37): Newly created order ID
* OrdStatus (39) = A for an order being accepted, but not yet confirmed
* ClOrdID (11): Unique identifier as assigned by the buy-side
* ExecType (150) = A for an order being accepted, but not yet confirmed
* ExecType (150) = I will also be sent when a trigger order is confirmed but not yet triggered
## Request
---
## OrderCancelReject (35=9)
OrderCancelReject (35=9) The Order Cancel Reject (9) message is issued by the broker upon receipt of a cancel request or cancel/replace request message which cannot be honored. Requests to change price or decrease quantity are executed only when an outstanding quantity exists. Filled orders cannot be changed (i.e quantity reduced or price change. However, the broker/sellside may support increasing the order quantity on a currently filled order).
When rejecting a Cancel/Replace Request (or Cancel Request), the Cancel Reject (9) message should provide the ClOrdID (11) which was specified on the Cancel/Replace Request (or Cancel Request) message for identification, and the OrigClOrdId should be that of the last accepted order (except in the case of CxlRejReason (102) = "Unknown Order".
---
## OrderCancelReplaceRequest (35=G)
OrderCancelReplaceRequest (35=G) Cancel/Replace will be used to change any valid attribute of an open order (i.e. reduce/increase quantity, change limit price, change instructions, etc.),
Requests which cannot be processed will be rejected using the Cancel Reject (9) message. The Cancel Reject (9) message should provide the ClOrdID (11) and OrigClOrdID (41) values which were specified on the Cancel/Replace Request message for identification.
**Response Attributes:**
* MsgType (35) = 8
* OrderID (37): Newly created order ID
* OrdStatus (39) = A for an order being accepted, but not yet confirmed
* ClOrdID (11): Unique identifier as assigned by the buy-side
* ExecType (150) = A for an order being accepted, but not yet confirmed
* ExecType (150) = I will also be sent when a trigger order is confirmed but not yet triggered
See FIX Spot Order Life Cycle and ExecutionReport for details.
## Request
---
## OrderCancelRequest (35=F)
OrderCancelRequest (35=F) Cancels an existing order on the Exchange (asynchronous)
This call is asynchronous, so the response as ExecutionReport with Pending New is simply an acceptance of the request, but not necessarily mean it is confirmed into order book.
The drop copy subscription can be used to check when the order is successfully cancelled.
See FIX Spot Order Life Cycle and ExecutionReport for details.
**Response Attributes:**
An ExecutionReport (8) with ExecType=6 (Pending Cancel) for acceptance of the cancel request, pending for confirmation. Besides, OrderCancelReject (9) can be returned if cancel reject happens.
* MsgType (35) = 8 for pending cancel or 35=9 for cancel reject
* OrderID (37): Newly created order ID
* OrdStatus (39) = 6 for an order cancel request being accepted, but not yet confirmed
* ClOrdID (11): Unique identifier as assigned by the buy-side
* OrigClOrdID (41): Original unique identifier as assigned by the buy-side
* ExecType (150) = 6 for an order cancel request being accepted, but not yet confirmed
See FIX Spot Order Life Cycle, ExecutionReport and OrderCancelReject for details.
## Request
---
## FIX Order Management
Order Management flow for trading operations on the Crypto.com Exchange via FIX protocol.
This flow supports:
- **Order Entry**: Create new orders (35=D NewOrderSingle), modify existing orders (35=G OrderCancelReplaceRequest), and cancel orders (35=F OrderCancelRequest, 35=q OrderMassCancelRequest)
- **Execution Reports**: Receive order confirmations, fills, and status updates (35=8 ExecutionReport)
- **Order Status**: Query current order status (35=H OrderStatusRequest)
- **Rejections**: Handle order and cancel rejections (35=9 OrderCancelReject, 35=j BusinessMessageReject)
## Related Documentation
- [FIX Introduction](exchange-fix-protocol.info.mdx) — API overview, authentication, endpoints, and message structure
- [FIX Session Management](fix-session-management.tag.mdx) — Session management, logon/logout, and heartbeat messages
---
## OrderMassCancelReport (35=r)
OrderMassCancelReport (35=r) The Order Mass Cancel Report is used to acknowledge an Order Mass Cancel Request. Note that each affected order that is canceled is acknowledged with a separate Execution Report (8) or Order Cancel Reject (9) message.
---
## OrderMassCancelRequest (35=q)
OrderMassCancelRequest (35=q) Cancels all orders for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response as OrderMassCancelReport is simply an acceptance of the request, but not necessarily mean it is confirmed into order book.
The drop copy subscription can be used to check when the order is successfully cancelled with ExecutionReport or rejected with OrderCancelReject message.
From the drop copy, for each respective order, Execution Report (8) with ExecType=6 (Pending Cancel) and/or ExecType=4 (Cancelled) for acceptance and confirmation of the cancel request respectively. Besides, OrderCancelReject (9) can be returned if cancel reject happens.
**Response Attributes:**
See OrderMassCancelReport for details.
## Request
---
## OrderStatusRequest (35=H)
OrderStatusRequest (35=H) Get details on a particular OPEN Orders only in Order Management Flow. Not available in Drop Copy Flow.
**Request Attributes:**
* Symbol (55): Required
* ClOrdID (11): Unique identifier for Order as assigned by the buy-side, either tag11 or tag37 must be specified
* OrderID (37): OrderID of the order to request, either tag11 or tag37 must be specified
**Response Attributes:**
An ExecutionReport (8) with ExecType=I (Order Status) will be returned.
* MsgType (35) = 8
* ExecType (150) = I
* TotNumReports (911): Must be 0 to indicate there is no match, otherwise this tag will not be populated
* LastRptRequested (912): Must be Y
**Order status request rejected for unknown order:**
* MsgType (35) = 8
* ExecType (150) = I
* OrdStatus (39) = 8 Rejected
* CumQty (14) = 0
* LeavesQty (151) = 0
* OrdRejReason (103): 5 = Unknown Order, 8 = Stale Order, 13 = Incorrect quantity, 99 = Other
See ExecutionReport for details.
## Request
---
## Reject (35=3)
Reject (35=3) The Reject (3) message should be issued when a message is received but cannot be properly processed due to a session-level rule violation. An example of when a reject may be appropriate would be the receipt of a message with invalid basic data (e.g. MsgType (35) = &) which successfully passes de-encryption, CheckSum (10) and BodyLength (9) checks.
Generation and receipt of a Reject (3) message indicates a serious error that may be the result of faulty logic in either the sending or receiving application.
If the sending application chooses to retransmit the rejected message, it should be assigned a new sequence number.
Note: receiving a Reject (3) for a message does NOT imply that the message has not been processed. The reject simply indicates that the message was improperly formatted or contained invalid data.
---
## ResendRequest (35=2)
ResendRequest (35=2) The resend request is sent by the receiving application to initiate the retransmission of messages. This function is utilized if a sequence number gap is detected, if the receiving application lost a message, or as a function of the initialization process.
The resend request can be used to request a single message, a range of messages or all messages subsequent to a particular message.
Note: the sending application may wish to consider the message type when resending messages; e.g. if a new order is in the resend series and a significant time period has elapsed since its original inception, the sender may not wish to retransmit the order given the potential for changed market conditions. (The Sequence Reset-GapFill (4) message is used to skip messages that a sender does not wish to resend.)
Note: it is imperative that the receiving application process messages in sequence order, e.g. if message number 7 is missed and 8-9 received, the application should ignore 8 and 9 and ask for a resend of 7-9, or, preferably, 7-0 (0 represents infinity). This latter approach is strongly recommended to recover from out of sequence conditions as it allows for faster recovery in the presence of certain race conditions when both sides are simultaneously attempting to recover a gap.
Request types:
* To request a single message: BeginSeqNo (7) = EndSeqNo (16)
* To request a range of messages: BeginSeqNo (7) = first message of range, EndSeqNo (16) = last message of range
* To request all messages subsequent to a particular message: BeginSeqNo (7) = first message of range, EndSeqNo (16) = 0 (represents infinity)
FIX Sequence Number Resent scenarios:
Case 1: After logon request (35=A), CDC found that there are missing sequence number and requires retransmission of messages from client. ResendRequest (35=2) sent by CDC.
Case 2: After logon request (35=A), client found that there are missing sequence number and requires retransmission of messages from CDC. ResendRequest (35=2) sent by client.
Case 3: ResendRequest (35=2) sent by client and CDC after Logon (35=A) acknowledgement.
## Request
---
## SecurityDefinitionRequest (35=c)
SecurityDefinitionRequest (35=c) The FIX Client could request the details of a tradable instrument by sending a Security Definition Request (35=c) message to the gateway. The Symbol (55) is used as the unique identifier of an instrument.
**Response Attributes:**
See SecurityDefinition for details.
## Request
---
## SecurityDefinition (35=d)
SecurityDefinition (35=d) After received (35=c), gateway will acknowledge and send a Security Definition (35=d) message to the client. The subscribed clients will be sent a Security Definition (35=d) message for each new instrument. Client will receive multiple Security Definition (35=d) when receiving (35=c,321=3)
---
## SecurityListRequest (35=x)
SecurityListRequest (35=x) Security List is an aggregation of instrument definitions. It is useful when the FIX Client want get all instrument definitions, or expect to get numerous instrument definitions in one go. The FIX Client should send a Security List Request (35=x) message to the gateway.
**Response Attributes:**
See SecurityList for details.
## Request
---
## SecurityList (35=y)
SecurityList (35=y) After receiving (35=x), the Gateway will acknowledge this message by sending one or more Security List (35=y) message, because the gateway divides the list of instruments into chunks, and each chunk will construct a Security List (35=y) message so as to avoid an excessively large Security List (35=y) message. The subscribed clients will be sent a Security Definition (35=d) message for each new instrument. ie. One instrument with one (35=y) only.
---
## SequenceReset (35=4)
SequenceReset (35=4) The Sequence Reset message has two modes: Gap Fill mode and Reset mode.
**Gap Fill mode**
Gap Fill mode is used in response to a Resend Request (2) when one or more messages must be skipped over for the following reasons:
* During normal resend processing, the sending application may choose not to send a message (e.g. an aged order).
* During normal resend processing, a number of administrative messages are skipped and not resent (such as Heart Beats, Test Requests).
Gap Fill mode is indicated by GapFillFlag (123) field = "Y".
If the GapFillFlag (123) field is present (and equal to "Y"), the MsgSeqNum (34) should conform to standard message sequencing rules (i.e. the MsgSeqNum (34) of the Sequence Reset (4) GapFill mode message should represent the beginning MsgSeqNum (34) in the GapFill range because the remote side is expecting that next message sequence number).
**Reset mode**
Reset mode involves specifying an arbitrarily higher new sequence number to be expected by the receiver of the Sequence Reset (4)-Reset mode message, and is used to reestablish a FIX session after an unrecoverable application failure.
Reset mode is indicated by the GapFillFlag (123) field = "N" or if the field is omitted.
If the GapFillFlag (123) field is not present (or set to N), it can be assumed that the purpose of the Sequence Reset (4) message is to recover from an out-of-sequence condition. Sequence Reset (4) - Reset should NOT be used as a normal response to a Resend Request (2) (use Sequence Reset (4) - Gap Fill mode). The Sequence Reset (4) - Reset should ONLY be used to recover from a disaster situation which cannot be recovered via the use of Sequence Reset (4) - Gap Fill.
**Rules for processing all Sequence Reset messages:**
* The sending application will initiate the Sequence Reset (4). The message specifies NewSeqNo (36) to reset to as the value of the next sequence number immediately following the messages being skipped.
* The Sequence Reset (4) can only increase the sequence number.
* If a sequence reset is received attempting to decrease the next expected sequence number the message should be rejected and treated as a serious error.
* One must be careful to ignore the duplicate Sequence Reset (4)-GapFill mode which is attempting to lower the next expected sequence number.
## Request
---
## FIX Session Management
Session-level messages for connection management, authentication, and message recovery.
## Starting a Session
FIX API runs the server side of the FIX connection ("acceptor"). Sequence numbers start at 1 and must be incremented with every message. Messages with duplicate or out-of-order sequence numbers will be rejected. We never reset sequence numbers on the server side during the logon workflow.
**Standard Session Recovery:**
1. Send 35=2 (ResendRequest) with the needed sequence number range
2. Receive replay messages with PossDupFlag=Y. Apply the changes based on standard FIX protocol. If a message with this sequence number has been previously received, ignore message; if not, process normally
3. Continue trading
## Ending a Session
The client may send the server an optional Logout (35=5) message, but the exchange will not interpret its absence as being an abnormal condition.
Under certain conditions, the server may send the client a Logout (35=5) message where the Text (58) field contains the reason.
## FIX Gateway Maintenance
The FIX gateway maintenance (Order Management flow only) will be carried out on the **second Thursday of each month, 07:05-07:15 UTC**.
Please disconnect on 07:04 UTC and reconnect on 07:15 UTC with sequence number 1/1.
**Other options for client preferences:**
- **Option 1:** Sequence number resets require clients to LOGOFF and then LOGIN again using the Logon (35=A) message with the ResetSeqNumFlag (141) set to 'Y'. This resets the sequence numbers on both sides. Clients are free to perform this action whenever is convenient for their own schedule and set-up.
- **Option 2:** Crypto.com FIX connections shall establish a cap to prevent sequence number counter overflow. Our FIX engine shall trigger disconnection and reset the sequence number to 1/1, when either the inbound or outbound sequence number reaches 2,147,480,000.
## Related Documentation
- [FIX Introduction](exchange-fix-protocol.info.mdx) — API overview, authentication, endpoints, and message structure
---
## TestRequest (35=1)
TestRequest (35=1) The Test Request (1) message forces a heartbeat from the opposing application. The Test Request (1) message checks sequence numbers or verifies communication line status. The opposite application responds to the Test Request (1) with a Heartbeat (0) containing the TestReqID (112).
The TestReqID (112) verifies that the opposite application is generating the heartbeat as the result of Test Request (1) and not a normal timeout. The opposite application includes the TestReqID (112) in the resulting Heartbeat (0). Any string can be used as the TestReqID (112) (one suggestion is to use a timestamp string).
## Request
---
## Generating the API Key
Before sending any requests, you'll need to generate a new API key.
This can be done in the Exchange website under **User Center > API**.
After generating the key, there are two things you need to carefully note down:
- **API Key**
- **Secret Key**
API Key and Secret are randomly generated by the system and cannot be modified. Default settings will be set to "Can Read" only, and you have the option 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.
---
## Change Log
- **2025-08-29** - Update description on tag6616, tag10060, tag60 and tag52
- **2025-11-13** - Update 35=D, added tag20100 ReceiveWindow
- **2025-07-30** - Update 35=H, not available for Drop Copy session
- **2025-07-09** - Update 35=D, tag18=8 SMART_POST_ONLY
- **2025-06-26** - Added 35=G for OrderCancelReplaceRequest
- **2025-05-29** - Update 35=V, tag MarketDepth(264) include market depth 1
- **2025-04-23** - Update FIX housekeeping period date
- **2025-02-06** - Added tag 10060 into tag 35=8
- **2024-10-25** - Added tag 20101 and tag 20102 into tag 35=8
- **2024-09-26** - Added tag 880 TrdMatchID into tag 35=8
- **2024-09-10** - FIX 3.0 initial
- **2024-06-28** - Added Self Trade Prevention (STP) feature
- **2023-10-03** - Added tag544=2 for margin trading in 35=D
- **2023-04-25** - Added 35=W for market data
- **2023-04-17** - Update 35=D, update tag1107 remove '=I', '=M'
- **2023-04-17** - Updated details on 35=X, NoMDEntries(268)
- **2023-02-23** - Add wait interval in 35=A
- **2023-02-06** - Added tag 278 include details with order books
- **2023-02-02** - MDS 2.0 initial
- **2023-02-01** - Added tag18 in execution report
- **2022-12-02** - Update on tag 35=2
- **2022-12-01** - Update description on tag 20001
- **2022-11-22** - Update the default COMPIDs
- **2022-11-18** - Included the response and reason codes
- **2022-11-14** - Update tag 1107 TriggerPriceType description
- **2022-10-18** - Updated cancellation request tag 35=F
- **2022-09-08** - Updated logon requests
- **2022-06-30** - Updated mass order request
- **2022-03-21** - Initial v3 API
---
## FIX Dictionary
Our FIX API implementation is based on the FIX Protocol 4.4 specifications, and on top of it we also include some tags from other versions of the FIX Specification, as well as some User Defined Fields.
We provide a custom dictionary in the QuickFIX XML format, which is also compatible with various FIX engine implementations.
---
## FIX Endpoints
To establish a FIX session, FIX clients must setup/use the AWS private link connection.
### UAT Sandbox
| FIX Gateway | FIX Endpoint | Sender Comp ID | Target Comp ID |
|-------------|--------------|----------------|----------------|
| User Data (Order Management) | tcp://uat1-fix-ud-f18a.crypto.local:31301 | UAT1.CLIENT_NAME.UD.00 | UAT1.CDC.UD |
| User Data (Drop Copy) | tcp://uat1-fix-uc-f18a.crypto.local:30300 | UAT1.CLIENT_NAME.UC.00 | UAT1.CDC.DC |
| Market Data (BTC related) | tcp://uat1-fix-md-f18a.crypto.local:34402 | UAT1.CLIENT_NAME_BTC.MD.00 | UAT1.CDC.MD |
| Market Data (ETH related) | tcp://uat1-fix-md-f18a.crypto.local:34403 | UAT1.CLIENT_NAME_ETH.MD.00 | UAT1.CDC.MD |
| Market Data (OTHERS related) | tcp://uat1-fix-md-f18a.crypto.local:3440[5-7] | UAT1.CLIENT_NAME_OTHERS.MD.00 | UAT1.CDC.MD |
### Production
| FIX Gateway | FIX Endpoint | Sender Comp ID | Target Comp ID |
|-------------|--------------|----------------|----------------|
| User Data (Order Management) | tcp://prd3-fix-ud-f18b.crypto.local:31301 | PRD3.CLIENT_NAME.UD.00 | PRD3.CDC.UD |
| User Data (Drop Copy) | tcp://prd3-fix-uc-f18b.crypto.local:30300 | PRD3.CLIENT_NAME.UC.00 | PRD3.CDC.UC |
| Market Data (BTC related) | tcp://prd3-fix-md-f18b.crypto.local:34402 | PRD3.CLIENT_NAME_BTC.MD.00 | PRD3.CDC.MD |
| Market Data (ETH related) | tcp://prd3-fix-md-f18b.crypto.local:34403 | PRD3.CLIENT_NAME_ETH.MD.00 | PRD3.CDC.MD |
| Market Data (OTHERS related) | tcp://prd3-fix-md-f18b.crypto.local:3440[5-7] | PRD3.CLIENT_NAME_OTHERS.MD.00 | PRD3.CDC.MD |
### Market Data Port Assignment
- **BTC related pairs** - Port 34402 (Note: ETH/BTC is NOT included on this instance)
- **ETH related pairs** - Port 34403 (Note: ETH/BTC is included on this instance)
- **Others** - Port 34405 [0-9A-D], Port 34406 [E-M], Port 34407 [N-Z]
---
## FIX API
## Introduction
Welcome to the Crypto.com Exchange FIX API reference documentation.
FIX (Financial Information eXchange) is a standard electronic messaging protocol which can be used to place orders, receive order updates and executions, and cancel orders. Our FIX API is based on the FIX 4.4 specification and modeled after FIX implementations of other popular cryptocurrency exchanges.
The FIX API is available across 3 servers: the user data server (order management), user data server (drop copy), and the market data server.
Users who are less familiar with FIX can also consider using the [REST API](/docs/api/rest-introduction) or [WebSocket API](/docs/api/websocket-introduction).
---
## Rate Limits
| FIX Endpoint | Limit |
|--------------|-------|
| Order Entry | 2500 requests per second |
| Market Data | 20 requests per second |
**Important Note:** We recommend adding a 1-second sleep after establishing the FIX connection, and before requests are sent. This will avoid occurrences of rate-limit errors, as the rate limits are pro-rated based on the calendar-second that the connection was opened.
---
## Standard Header and Trailer
This documentation uses `|` to represent the FIX field separator (byte 0x01). It should be replaced by 0x01 in actual messages.
### Standard Header
The header identifies the message type, length, destination, sequence number, origination point and time.
| Tag | Name | Type | Required | Description |
|-----|------|------|----------|-------------|
| 8 | BeginString | string | Y | Must be "FIX.4.4" |
| 9 | BodyLength | number | Y | Length of the message body in bytes |
| 35 | MsgType | string | Y | Message Type |
| 34 | MsgSeqNum | number | Y | Integer message sequence number |
| 43 | PossDupFlag | boolean | N | Indicates possible retransmission of message with this sequence number |
| 49 | SenderCompID | string | Y | See FIX Endpoints for details |
| 56 | TargetCompID | string | Y | See FIX Endpoints for details |
| 52 | SendingTime | UTCTimestamp | Y | Time when the message is being sent out from FIX Gateway |
| 97 | PossResend | boolean | N | Indicates that message may contain information sent under another sequence number |
**Processing PossDupFlag and PossResend:**
- **PossDupFlag (43=Y)** — if a message with this sequence number has been previously received, ignore message; if not, process normally.
- **PossResend (97=Y)** — forward message to application and determine if previously received (i.e. verify order id and parameters).
### Standard Trailer
Each FIX message is terminated by a Standard Trailer as a message delimiter as well as containing the checksum value.
| Tag | Name | Type | Required | Description |
|-----|------|------|----------|-------------|
| 10 | CheckSum | string | Y | Three bytes, simple checksum. Always last field in message |
---
## Account Balance and Positions
Retrieve real-time and historical snapshots of wallet balances, open positions, margin requirements, and collateral status. Use these endpoints to monitor account health, risk exposure, and available trading capacity.
## Account Balance
The user balance response provides a comprehensive view of the account:
- **Available balance** — funds available for new positions and withdrawals
- **Margin balance** — total collateral value (cash + collateral-eligible tokens after haircut)
- **Initial margin (IM)** — collateral required to open current positions and orders
- **Maintenance margin (MM)** — minimum collateral threshold to avoid liquidation
- **Position balance** — per-token breakdown showing quantity, market value, haircut rate, and collateral contribution
If margin balance falls below maintenance margin, the account enters liquidation.
## Positions
The positions endpoint returns all open derivative contracts, including instrument name, quantity (signed to indicate direction), position cost, and session PnL. For real-time mark price, liquidation price, and margin requirements, subscribe to the `user.positions` WebSocket channel.
## Subaccounts
Master accounts can create subaccounts to isolate trading activity. Use the subaccount transfer endpoint to move funds between accounts.
---
## Advanced Order Management
Advanced Order Management provides trigger orders and multi-leg execution strategies beyond basic LIMIT and MARKET orders. Use these endpoints for conditional order execution based on price triggers.
## Trigger Orders
Trigger orders activate when a reference price condition is met. Use [`private/advanced/create-order`](/docs/api/rest/private-advanced-create-order) to create trigger orders.
| Type | Description |
|------|-------------|
| `STOP_LOSS` | Converts to a market order when trigger price is reached. Used to limit losses. |
| `STOP_LIMIT` | Converts to a limit order when trigger price is reached. Offers price control on stop execution. |
| `TAKE_PROFIT` | Market order activated when price moves favorably to the trigger level. Used to lock in gains. |
| `TAKE_PROFIT_LIMIT` | Limit order activated when price moves favorably to the trigger level. |
Trigger orders require:
- `ref_price` — the trigger price
- `ref_price_type` — reference price source: `MARK_PRICE` (default), `INDEX_PRICE`, or `LAST_PRICE`
## Multi-Leg Strategies
Multi-leg orders link multiple orders together with conditional execution logic.
| Strategy | Description | Endpoint |
|----------|-------------|----------|
| **OCO** (One-Cancels-Other) | Two orders where filling one cancels the other. Typically pairs a take-profit with a stop-loss. | [`private/advanced/create-oco`](/docs/api/rest/private-advanced-create-oco) |
| **OTO** (One-Triggers-Other) | Primary order triggers a secondary order when filled. Used to attach TP/SL to an entry order. | [`private/advanced/create-oto`](/docs/api/rest/private-advanced-create-oto) |
| **OTOCO** (One-Triggers-OCO) | Primary order triggers an OCO pair when filled. Entry order with both TP and SL attached. | [`private/advanced/create-otoco`](/docs/api/rest/private-advanced-create-otoco) |
## Contingency Types
Multi-leg orders use contingency types to define the relationship between legs:
| Type | Description |
|------|-------------|
| `OCO` | One-Cancels-Other: two orders, one cancels when the other fills |
| `SPOT_ATTACH` | Attach trigger orders to a spot position |
| `DERIV_ATTACH` | Attach trigger orders to a derivatives position (supports isolated margin) |
## Order Management
- [`private/advanced/amend-order`](/docs/api/rest/private-advanced-amend-order) — modify trigger price or quantity
- [`private/advanced/cancel-order`](/docs/api/rest/private-advanced-cancel-order) — cancel a single advanced order
- [`private/advanced/cancel-all-orders`](/docs/api/rest/private-advanced-cancel-all-orders) — cancel all advanced orders for an instrument
- [`private/advanced/get-open-orders`](/docs/api/rest/private-advanced-get-open-orders) — retrieve open advanced orders
- [`private/advanced/get-order-history`](/docs/api/rest/private-advanced-get-order-history) — retrieve advanced order history
## Real-Time Updates
Subscribe to `user.advanced.order` for real-time advanced order lifecycle events.
---
## Crypto.com Exchange API v1
Version: 1.0.0
Crypto.com Exchange API v1
## Welcome
Welcome to the Crypto.com Exchange API v1 reference documentation.
The Crypto.com Exchange API v1 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.
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, as well as sample requests and code snippets in JavaScript, Python which can be viewed on the right.
### Notes on Exchange Upgrade and API Versions
- Exchange v1 API is the latest version of API which can trade Spot / Derivatives / Margin.
- Derivatives v1 API has been upgraded into Exchange v1 API with additional capabilities for Spot Trading / Margin Trading / Wallet Management. As Exchange v1 API is a superset of Derivatives v1 API, existing customer can continue using the same for trading.
- For full details about the exchange upgrade, please refer to this (blog post)[https://crypto.com/product-news/introducing-the-gen-3-0-crypto-com-exchange] with FAQ documents.
## Breaking Change Schedule
- On 2025-12-17 8:00 UTC,
The current trigger order creation/cancellation will be migrated to Advanced Order Management API.
- On 2025-02-27 8:00 UTC,
For `book.{instrument_name}.{depth}`, the full snapshot subscription (`book_subscription_type=SNAPSHOT`) `100ms` frequency is removed.
Customers wishing to continue with the faster `100ms` frequency should switch to the delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`).
This higher performing subscription benefits the user with reduced bandwidth/processing compared to the snapshot subscription.
For a transition period, users subscribing to the removed `100ms` snapshot will receive the `500ms` subscription.
The `book.{instrument_name}` subscription (default depth) will be removed.
Customers should use the explicit `book.{instrument_name}.{depth}` subscription and specify the required depth.
For a transition period, users subscribing to the removed subscription will receive the default `50` depth subscription.
- These changes will take place around 17 December 2023 8:00 UTC.
- Market Data wildcard ticker subscription will be removed. Users should use the instrument specific subscription.
## Change Log
- **2026-05-21**
- `public/get-instruments` response updated, new field `product_type` was added
- Trading Bot API section was added:
`private/bot/create-trading-bot` (DCA, TWAP, GRID, FUNDING_ARBITRAGE)
`private/bot/terminate-trading-bot`
`private/bot/update-trading-bot`
`private/bot/pause-trading-bot`
`private/bot/resume-trading-bot`
`private/bot/get-trading-bots`
`private/bot/get-trading-bot-executions`
- **2026-05-07**
- Advanced Order Management API section was updated for DerivAttach
- `private/advanced/create-oto` and `private/advanced/create-otoco` — contingency type is now resolved from instrument type: spot instruments create SPOT_ATTACH, derivative instruments create DERIV_ATTACH. DerivAttach supports `isolation_id`, `leverage`, `isolated_margin_amount` on the primary leg and `ISOLATED_MARGIN` in `exec_inst`. Trigger legs inherit isolation mode from the parent.
- `private/advanced/create-order` — `attach_order_id` now applies to both SpotAttach and DerivAttach. New optional field `attach_isolation_id` for DerivAttach attach-to-position (derivatives only).
- `private/advanced/cancel-oto` and `private/advanced/cancel-otoco` — updated to cover both SPOT_ATTACH and DERIV_ATTACH.
- `private/advanced/cancel-all-orders` — new optional field `position_type` (CROSS_MARGIN, ISOLATED_MARGIN).
- `private/advanced/get-open-orders`, `private/advanced/get-order-detail`, `private/advanced/get-order-history`, and `user.advance.order` — response attributes extended with `exchange_order_id`, `ref_price`, `ref_price_type`, `reject_reason`, `attach_isolation_id`, `isolation_id`, `isolation_type`, `leverage`, `isolated_margin_amount`. `contingency_type` now includes DERIV_ATTACH.
- `private/advanced/amend-order` — corrected required/optional flags: `new_price` is Y, `new_quantity` is Y, `new_ref_price` is N.
- **2026-04-29**
- Fee Credits
- `private/get-fee-credit-balances` was added
- `private/get-trades` response updated, new field `fee_credits` was added
- `user.trade.{instrument_name}` response updated, new field `fee_credits` was added
- **2026-04-07**
- `private/get-accounts` response updated, new field `hierarchy` was added
- **2026-04-01**
- `private/create-order` request updated, `REDUCE_ONLY` was added to `exec_inst`
- **2026-01-08**
- Add support for isolated position
- `private/create-isolated-margin-transfer` was added
- `private/change-isolated-margin-leverage` was added
- `private/user-balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/user-balance-history` response updated, new field `i` was added
- `private/get-subaccount-balances` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/get-positions` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/create-order` request updated, new optional fields `isolation_id`, `leverage`, `isolated_margin_amount` were added, `exec_inst` added support for `ISOALTED_MARGIN`
- `private/close-position` request updated, new optional field `isolation_id` was added
- `private/get-open-orders` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-detail` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-history` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-trades` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-transactions` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `user.order.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.trade.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `user.positions` response updated, new fields `isolation_id`, `leverage`, `isolation_type`, `liquidation_price` and `isolated_margin_balance` were added
- `user.account_risk` response updated, new fields `total_isolated_cash_balance`, `isolated_positions` were added
- `user.position_balance` response updated, new field `isolated_positions` was added
- **2025-03-26**
- `transaction_time` was added into `user.order.{instrument_name}`
- **2025-11-18**
- `public/get-risk-parameters` was added new columns
- **2025-10-16**
- `Advanced Order Management API` section was updated
- **2025-07-17**
- `private/fiat/fiat-deposit-info` was added
- `private/fiat/fiat-deposit-history` was added
- `private/fiat/fiat-withdraw-history` was added
- `private/fiat/fiat-create-withdraw` was added
- `private/fiat/fiat-get-bank-accounts` was added
- `private/fiat/fiat-transaction-quota` was added
- `private/fiat/fiat-transaction-limit` was added
- **2025-07-04**
- `private/create-order` exec_inst was added `SMART_POST_ONLY`
- `private/create-order-list (LIST)` exec_inst was added `SMART_POST_ONLY`
- `private/get-open-orders` exec_inst was added `SMART_POST_ONLY`
- `private/get-order-detail` was added, exec_inst was added `SMART_POST_ONLY`
- `private/get-order-history` exec_inst was added `SMART_POST_ONLY`
- **2025-06-10**
- `private/amend-order` was added
- `public/get-announcements` was added
- **2025-05-29**
- transaction_time_ns field was added into `user.order.{instrument_name}` response
- **2025-03-14**
- Removed deprecated attributes system_label in `private/get-accounts`
- **2025-03-06**
- Removed deprecated `book.{instrument_name}` default book subscription
- Removed deprecated 100ms interval from full snapshot `book.{instrument_name}.{depth}` book subscription
- **2025-03-04**
- Remove section: `Unified Wallet and System Label`
- **2025-01-27**
- `book.{instrument_name}.{depth}` - The following additional update frequencies are now supported:
Full snapshot subscription (`book_subscription_type=SNAPSHOT`) `500ms`
Delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`) `100ms`
- **2024-12-11**
- `private/create-order` fee_instrument_name was added
- **2024-10-02**
- `public/get-risk-parameters` was added
- **2024-08-15**
- `private/get-fee-rate` was added
- `private/get-instrument-fee-rate` was added
- **2024-07-12**
- Staking API added:
`private/staking/stake`
`private/staking/unstake`
`private/staking/get-staking-position`
`private/staking/get-staking-instruments`
`private/staking/get-open-stake`
`private/staking/get-stake-history`
`private/staking/get-reward-history`
`private/staking/convert`
`private/staking/get-open-convert`
`private/staking/get-convert-history`
`public/staking/get-conversion-rate`
- **2024-06-27**
- `private/create-order` self-trade prevent (STP) was added
- `private/create-order-list (LIST)` self-trade prevent (STP) was added
- **2024-02-12**
- `public/get-trades`, `trade.{instrument_name}` subscription, clarification for the public trade side field
- Side is the side of the taker order
- `book.{instrument_name}.{depth}` clarifications for book delta sequence number handling and re-subscription
- **2024-01-04**
- Market data websocket subscription enhancements:
- `book.{instrument_name}` - The `subscription` result value is now explicit
e.g. previous `"subscription": "book.BTC_USD"` -\> new `"subscription": "book.BTC_USD.50"`
- `book.{instrument_name}.{depth}` - For delta updates, the fixed 500ms delta full book snapshot heartbeat is replaced with empty delta in the case of no book changes
- `ticker` - Documented existing 'bs' and 'ks' fields (bid/ask size)
- `settlement` - For wildcard subscription, the `subscription` result value is now explicit
e.g. previous `"subscription": "settlement"` -\> new `"subscription": "settlement.BTCUSD-231124"`
- Applied consistent field ordering for all market data subscriptions (`book`, `ticker`, `trade`, `candlestick`, `index`, `mark`, `settlement`, `funding`, `estimatedfunding`).
Result fields are always in the following order:
`id, method, code, instrument_name, subscription, channel`
- Market data REST `public/get-trades`
- Added additional `tn` nanoseconds timestamp field to the trade response
- Clarified timestamp pagination parameters
- **2023-12-18**
- Market Data wildcard ticker subscription removed. Users should use the instrument specific subscription.
- **2023-12-11**
- Introduced Market Data subscription limiting. Refer to Market Data Websocket Subscription Limits for more details
- **2023-10-31**
- `user.balance`, `private/user-balance` will be updated:
1. Existing field total_margin_balance will represent new margin balance calculation without haircut.
2. Existing field total_initial_margin previously is made up of position IM only. On effective date, this field will represent the total sum of total_position_im + total_haircut
3. New field total_position_im will be introduced to represent initial margin requirement to support open positions and orders
4. New field total_haircut will be introduced to represent the total haircut on eligible collateral token assets. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- `user.balance`, `user.account_risk`, `private/user-balance`, `private/get-subaccount-balances` will be updated:
1. New field collateral_eligible will be introduced to indicate if token is eligible Collateral
2. collateral_weight will be deprecated
3. New field haircut will be introduced to show haircut of eligible collateral token instead of collateral Weight. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- **2023-08-11**
- `private/create-order-list (LIST)` for batch order creation added
- `private/cancel-order-list (LIST)` for batch order cancel added
- **2023-07-31**
- Market Data Websocket Subscriptions is effective:
- `funding.{instrument_name}` - channel will return the fixed hourly rate that will settle at the end of the hour.
- `estimatedfunding.{instrument_name}` - channel will return the estimated hourly rate that will begin in the next interval.
- Added new "funding_rate" and "estimated_funding_rate" valuation types for public/get-valuations
- **2023-06-28**
- `private/get-deposit-history` added
- `private/get-withdrawal-history` added
- **2022-11-30**
- Support using `client_oid` to query in `private/get-order-detail` REST API
- **2022-11-10**
- `USD_Stable_Coin` (aka USD Bundle), will be renamed as `USD`. Customer can test the change in UAT from 2022-11-10 before the change is effective in PROD. Target date for PROD is TBD.
- Customer can input both `USD` and `USD_Stable_Coin` to mean the same USD Bundle.
- However, on response, `USD` will be used to mean USD Bundle, instead of `USD_Stable_Coin`.
- **2022-10-31**
- Added `private/create-order-list`, `private/create-subaccount-transfer` REST APIs
- Added `user.account_risk` and `user.position_balance` WebSocket subscriptions
- Added more `period` in `public/get-candlestick` `candlestick.{time_frame}.{instrument_name}` WebSocket subscription
- **2022-09-21** - Added **Unified Wallet and System Label** section, to illustrate the transition from multiple wallets into unified wallet.
- **2022-09-21** - Added new sub-account management endpoints: `private/get-accounts`, `private/create-subaccount-transfer`
- **2022-09-21** - Added new exchange wallet management endpoints: `private/create-withdrawal`, `private/get-deposit-address`, `private/get-curency-networks`
- **2022-09-21** - First publish, based on Derivative Exchange API v1.
## Common API References
### Naming Conventions
- All **methods and URLs** in **dash-case**
- All **parameters** in **snake_case**
- **Enums** in full **UPPERCASE** and **snake_case**
### Generating the API Key
Before sending any requests, generate a new API key on the Exchange website under **User Center** → **API**. Note down:
- **API Key**
- **Secret Key**
Default settings are "Can Read" only; you can add or remove permissions via the Web UI. You may optionally specify a whitelist of IP addresses; if set, the API can only be used from those IPs.
### REST API Root Endpoints
REST API requests must be sent with **Content-Type: application/json**.
| Environment | REST API |
|-------------|----------|
| **UAT Sandbox** | `https://uat-api.3ona.co/exchange/v1/{method}` |
| **Production** | `https://api.crypto.com/exchange/v1/{method}` |
### Websocket Root Endpoints
| Environment | Websocket (User API) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/user` |
| **Production** | `wss://stream.crypto.com/exchange/v1/user` |
| Environment | Websocket (Market Data) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/market` |
| **Production** | `wss://stream.crypto.com/exchange/v1/market` |
### Rate Limits
#### REST API
For authenticated calls, rate limits are per API method, per API key:
| Method | Limit |
|--------|-------|
| `private/create-order`, `private/cancel-order`, `private/cancel-all-orders` | 15 requests per 100ms each |
| `private/get-order-detail` | 30 requests per 100ms |
| `private/get-trades` | 1 request per second |
| `private/get-order-history` | 1 request per second |
| All others | 3 requests per 100ms each |
For public market data calls, rate limits are per API method, per IP address:
| Method | Limit |
|--------|-------|
| All | 100 requests per second each |
#### Staking
| Method | Limit |
|--------|-------|
| All | 50 requests per second each |
#### Websocket
| Method | Limit |
|--------|-------|
| User API | 150 requests per second |
| Market Data | 100 requests per second |
### Request Format
The following information applies to both REST API and websockets commands:
| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | long | Y | Request identifier (0 to 9,223,372,036,854,775,807). Response echoes the same id. |
| method | string | Y | The method to be invoked (e.g. `private/get-order-detail`). |
| params | object | Y | Parameters for the method. Use `{}` when a method has no parameters. |
| api_key | string | Depends | API key. Required for **private** methods (see Digital Signature). |
| sig | string | Depends | Digital signature. Required for **private** methods. |
| nonce | long | Y | Current timestamp in **milliseconds** since the Unix epoch. |
**⚠️ All numbers must be strings, and must be wrapped in double quotes. e.g. "12.34", instead of 12.34.**
### Digital Signature
For REST API, only 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 pass in the digital signature and API key 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 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.
Besides, for JavaScript client calling `private/get-order-detail` API, it is highly recommended to use STRING format of `order_id` in the JSON request payload, in order to guarantee the correctness of Digital Signature.
#### JavaScript Example
```javascript
const crypto = require("crypto-js");
const signRequest = (request_body, api_key, secret) => {
const { id, method, params, nonce } = request_body;
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)); }, "");
}
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);
const sigPayload = method + id + api_key + paramsString + nonce;
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",
method: "private/get-order-detail",
api_key: apiKey,
params: {
order_id: "53287421324"
},
nonce: "1587846358253",
};
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
```
#### Python Example
```python
API_KEY = "API_KEY"
SECRET_KEY = "SECRET_KEY"
req = {
"id": "14",
"method": "private/create-order-list",
"api_key": API_KEY,
"params": {
"contingency_type": "LIST",
"order_list": [
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "LIMIT",
"price": "0.24",
"quantity": "1.0"
},
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "STOP_LIMIT",
"price": "0.27",
"quantity": "1.0",
"trigger_price": "0.26"
}
]
},
"nonce": str(int(time.time() * 1000))
}
# First ensure the params are alphabetically sorted by key
param_str = ""
MAX_LEVEL = 3
def params_to_str(obj, level):
if level >= MAX_LEVEL:
return str(obj)
return_str = ""
for key in sorted(obj):
return_str += key
if obj[key] is None:
return_str += 'null'
elif isinstance(obj[key], list):
for subObj in obj[key]:
return_str += params_to_str(subObj, level + 1)
else:
return_str += str(obj[key])
return return_str
if "params" in req:
param_str = params_to_str(req['params'], 0)
payload_str = req['method'] + str(req['id']) + req['api_key'] + param_str + str(req['nonce'])
req['sig'] = hmac.new(
bytes(str(SECRET_KEY), 'utf-8'),
msg=bytes(payload_str, 'utf-8'),
digestmod=hashlib.sha256
).hexdigest()
```
#### C# Example
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
private const string API_KEY = "YOUR_API_KEY";
private const string API_SECRET = "YOUR_API_SECRET";
private static string GetSign(Dictionary request)
{
var paramsDict = request["params"] as Dictionary;
// Ensure the params are alphabetically sorted by key
// Note: For nested objects or lists, implement recursive sorting similar to JS/Python examples
string paramString = paramsDict != null
? string.Join("", paramsDict.Keys.OrderBy(key => key).Select(key => key + paramsDict[key]))
: "";
string sigPayload = request["method"].ToString()
+ request["id"].ToString()
+ API_KEY
+ paramString
+ request["nonce"].ToString();
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(API_SECRET)))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(sigPayload));
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
```
#### Java Example
```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiRequestJson {
private Long id;
private String method;
private Map params;
private String sig;
@JsonProperty("api_key")
private String apiKey;
private Long nonce;
}
//------------
public class SigningUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final int MAX_LEVEL = 3;
public static boolean verifySignature(ApiRequestJson apiRequestJson, String secret) {
try {
return genSignature(apiRequestJson, secret).equalsIgnoreCase(apiRequestJson.getSig());
} catch (Exception e) {
return false;
}
}
@SuppressWarnings("unchecked")
public static String getParamString(final Object paramObject) {
StringBuilder sb = new StringBuilder();
appendParamString(sb, paramObject, 0);
return sb.toString();
}
@SuppressWarnings("unchecked")
private static void appendParamString(final StringBuilder paramsStringBuilder, final Object paramObject, final int level) {
if (level >= MAX_LEVEL) {
paramsStringBuilder.append(paramObject.toString());
return;
}
if (paramObject instanceof Map) {
TreeMap params = new TreeMap<>((Map) paramObject);
for (Map.Entry entry : params.entrySet()) {
if (entry.getValue() instanceof Double) {
paramsStringBuilder
.append(entry.getKey())
.append((new BigDecimal(entry.getValue().toString()))
.stripTrailingZeros()
.toPlainString());
} else if (entry.getValue() instanceof List || entry.getValue() instanceof Map) {
paramsStringBuilder
.append(entry.getKey());
appendParamString(paramsStringBuilder, entry.getValue(), level + 1);
} else {
paramsStringBuilder
.append(entry.getKey())
.append(entry.getValue());
}
}
} else if (paramObject instanceof List) {
List list = (List) paramObject;
for (Object o : list) {
appendParamString(paramsStringBuilder, o, level + 1);
}
} else {
paramsStringBuilder.append(paramObject.toString());
}
}
public static String genSignature(ApiRequestJson apiRequestJson, String secret)
throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] byteKey = secret.getBytes(StandardCharsets.UTF_8);
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA256);
mac.init(keySpec);
String paramsString = "";
if (apiRequestJson.getParams() != null) {
paramsString += getParamString(apiRequestJson.getParams());
}
String sigPayload =
apiRequestJson.getMethod()
+ apiRequestJson.getId()
+ apiRequestJson.getApiKey()
+ paramsString
+ (apiRequestJson.getNonce() == null ? "" : apiRequestJson.getNonce());
byte[] macData = mac.doFinal(sigPayload.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(macData);
}
public static ApiRequestJson sign(ApiRequestJson apiRequestJson, String secret)
throws InvalidKeyException, NoSuchAlgorithmException {
apiRequestJson.setSig(genSignature(apiRequestJson, secret));
return apiRequestJson;
}
public static void main(String[] argv) throws InvalidKeyException, NoSuchAlgorithmException {
ApiRequestJson apiRequestJson = ApiRequestJson.builder()
.id(11L)
.apiKey("token")
.method("public/auth")
.nonce(1589594102779L)
.build();
System.out.println(genSignature(apiRequestJson, "secretKey"));
System.out.println(sign(apiRequestJson, "secretKey"));
}
}
```
### Response Format
| Name | Type | Description |
|------|------|-------------|
| id | long | Original request identifier (or -1 if omitted in request). |
| method | string | Method invoked. |
| result | object | Result object (present on success). |
| code | int | 0 for success; see Response and Reason Codes |
| message | string | Optional; server or error message. |
| original | string | Optional; original request as escaped string (for error cases). |
### Response and Reason Codes
#### 200 OK
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 200 | 0 | --:Success |
| 200 | 40401 | NOT_FOUND:Not found |
| 200 | 43012 | SELF_TRADE_PREVENTION:Canceled due to Self Trade Prevention |
#### 400 Bad Request
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 400 | 202 | ACCOUNT_IS_SUSPENDED:Account is suspended |
| 400 | 204 | DUPLICATE_CLORDID:Duplicate client order id |
| 400 | 207 | NO_MARK_PRICE:No mark price |
| 400 | 208 | INSTRUMENT_NOT_TRADABLE:Instrument is not tradable |
| 400 | 209 | INVALID_INSTRUMENT:Instrument is invalid |
| 400 | 213 | INVALID_ORDERQTY:Invalid order quantity |
| 400 | 218 | INVALID_ORDTYPE:Invalid order_type |
| 400 | 220 | INVALID_SIDE:Invalid side |
| 400 | 221 | INVALID_TIF:Invalid time_in_force |
| 400 | 222 | STALE_MARK_PRICE:Stale mark price |
| 400 | 223 | NO_CLORDID:No client order id |
| 400 | 224 | REJ_BY_MATCHING_ENGINE:Rejected by matching engine |
| 400 | 225 | EXCEED_MAXIMUM_ENTRY_LEVERAGE:Exceeds maximum entry leverage |
| 400 | 226 | INVALID_LEVERAGE:Invalid leverage |
| 400 | 227 | INVALID_SLIPPAGE:Invalid slippage |
| 400 | 228 | INVALID_FLOOR_PRICE:Invalid floor price |
| 400 | 229 | INVALID_REF_PRICE:Invalid ref price |
| 400 | 230 | INVALID_REF_PRICE_TYPE:Invalid ref price type |
| 400 | 308 | INVALID_PRICE:Invalid price |
| 400 | 314 | EXCEEDS_MAX_ORDER_SIZE:Exceeds max order size |
| 400 | 315 | FAR_AWAY_LIMIT_PRICE:Far away limit price |
| 400 | 318 | EXCEEDS_MAX_ALLOWED_ORDERS:Exceeds max allowed orders |
| 400 | 319 | EXCEEDS_MAX_POSITION_SIZE:Exceeds max position size |
| 400 | 401 | ACCOUNT_DOES_NOT_EXIST:Account does not exist |
| 400 | 408 | MARGIN_UNIT_IS_SUSPENDED:Margin unit is suspended |
| 400 | 30024 | MAX_AMOUNT_VIOLATED:If create-withdrawal call quantity > max_withdrawal_balance in user-balance api |
| 400 | 40001 | BAD_REQUEST:Bad request |
| 400 | 40002 | METHOD_NOT_FOUND:Method not found |
| 400 | 40003 | INVALID_REQUEST:Invalid request |
| 400 | 40004 | MISSING_OR_INVALID_ARGUMENT:Required argument is blank or missing |
| 400 | 40005 | INVALID_DATE:Invalid date |
| 400 | 40006 | DUPLICATE_REQUEST:Duplicate request received |
| 400 | 40102 | INVALID_NONCE:Nonce value differs by more than 60 seconds |
| 400 | 40107 | EXCEED_MAX_SUBSCRIPTIONS:Session subscription limit has been exceeded |
| 400 | 50001 | ERR_INTERNAL:Internal error |
| 400 | 50002 | DW_CREDIT_LINE_NOT_MAINTAINED:If create-withdrawal call breaches credit line check |
#### 401 Unauthorized
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 401 | 40101 | UNAUTHORIZED:Not authenticated, or key/signature incorrect |
| 401 | 40103 | IP_ILLEGAL:IP address not whitelisted |
| 401 | 40104 | USER_TIER_INVALID:Disallowed based on user tier |
#### 408 Request Timeout
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 408 | 40801 | REQUEST_TIMEOUT:Request has timed out |
#### 429 Too Many Requests
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 429 | 42901 | TOO_MANY_REQUESTS:Requests have exceeded rate limits |
#### 500 Internal Server Error
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 500 | 201 | NO_POSITION:No position |
| 500 | 203 | ACCOUNTS_DO_NOT_MATCH:Accounts do not match |
| 500 | 205 | DUPLICATE_ORDERID:Duplicate order id |
| 500 | 206 | INSTRUMENT_EXPIRED:Instrument has expired |
| 500 | 210 | INVALID_ACCOUNT:Account is invalid |
| 500 | 211 | INVALID_CURRENCY:Currency is invalid |
| 500 | 212 | INVALID_ORDERID:Invalid order id |
| 500 | 214 | INVALID_SETTLE_CURRENCY:Invalid settlement currency |
| 500 | 215 | INVALID_FEE_CURRENCY:Invalid fee currency |
| 500 | 216 | INVALID_POSITION_QTY:Invalid position quantity |
| 500 | 217 | INVALID_OPEN_QTY:Invalid open quantity |
| 500 | 219 | INVALID_EXECINST:Invalid exec_inst |
| 500 | 301 | ACCOUNT_IS_IN_MARGIN_CALL:Account is in margin call |
| 500 | 302 | EXCEEDS_ACCOUNT_RISK_LIMIT:Exceeds account risk limit |
| 500 | 303 | EXCEEDS_POSITION_RISK_LIMIT:Exceeds position risk limit |
| 500 | 304 | ORDER_WILL_LEAD_TO_IMMEDIATE_LIQUIDATION:Order will lead to immediate liquidation |
| 500 | 305 | ORDER_WILL_TRIGGER_MARGIN_CALL:Order will trigger margin call |
| 500 | 306 | INSUFFICIENT_AVAILABLE_BALANCE:Insufficient available balance |
| 500 | 307 | INVALID_ORDSTATUS:Invalid order status |
| 500 | 309 | MARKET_IS_NOT_OPEN:Market is not open |
| 500 | 310 | ORDER_PRICE_BEYOND_LIQUIDATION_PRICE:Order price beyond liquidation price |
| 500 | 311 | POSITION_IS_IN_LIQUIDATION:Position is in liquidation |
| 500 | 312 | ORDER_PRICE_GREATER_THAN_LIMITUPPRICE:Order price is greater than the limit up price |
| 500 | 313 | ORDER_PRICE_LESS_THAN_LIMITDOWNPRICE:Order price is less than the limit down price |
| 500 | 316 | NO_ACTIVE_ORDER:No active order |
| 500 | 317 | POSITION_NO_EXIST:Position does not exist |
| 500 | 320 | EXCEEDS_INITIAL_MARGIN:Exceeds initial margin |
| 500 | 321 | EXCEEDS_MAX_AVAILABLE_BALANCE:Exceeds maximum available balance |
| 500 | 406 | ACCOUNT_IS_NOT_ACTIVE:Account is not active |
| 500 | 407 | MARGIN_UNIT_DOES_NOT_EXIST:Margin unit does not exist |
| 500 | 409 | INVALID_USER:Invalid user |
| 500 | 410 | USER_IS_NOT_ACTIVE:User is not active |
| 500 | 411 | USER_NO_DERIV_ACCESS:User does not have derivative access |
| 500 | 412 | ACCOUNT_NO_DERIV_ACCESS:Account does not have derivative access |
| 500 | 415 | BELOW_MIN_ORDER_SIZE:Below Min. Order Size |
| 500 | 501 | EXCEED_MAXIMUM_EFFECTIVE_LEVERAGE:Exceeds maximum effective leverage |
| 500 | 604 | INVALID_COLLATERAL_PRICE:Invalid collateral price |
| 500 | 605 | INVALID_MARGIN_CALC:Invalid margin calculation |
| 500 | 606 | EXCEED_ALLOWED_SLIPPAGE:Exceed allowed slippage |
| 500 | 613 | INVALID_ISOLATION_ID:Invalid isolation ID |
| 500 | 614 | EXCEEDS_ISOLATED_POSITION_LIMIT:Exceeds maximum allowed number of isolated position |
| 500 | 615 | ACCOUNT_DOES_NOT_SUPPORT_ISOLATED_POSITION:Account does not support isolated position |
| 500 | 616 | CREATE_ISOLATED_POSITION_FAILED:Failed to create isolated position |
| 500 | 617 | DUPLICATED_INSTRUMENT_ORDER_FOR_ISOLATED_MARGIN:Account already have isolated position with same instrument |
| 500 | 618 | TOO_MANY_PENDING_ISOLATED_MARGIN_REQUESTS:Exceeds request limit for isolated margin order |
| 500 | 619 | UNSUPPORTED_OPERATION_ON_ISOLATED_POSITION:Unsupported operation on isolated position |
| 500 | 620 | CREATE_ISOLATED_POSITION_TIMEOUT:Request for create isolated position has timed out |
| 400 | 1110 | REDUCE_ONLY_REJECTED:Rejected REDUCE_ONLY create-order request |
| 500 | 43003 | FILL_OR_KILL:FOK order has not been filled and cancelled |
| 500 | 43004 | IMMEDIATE_OR_CANCEL:IOC order has not been filled and cancelled |
| 500 | 43005 | POST_ONLY_REJ:Rejected POST_ONLY create-order request (normally happened when exec_inst contains POST_ONLY but time_in_force is NOT GOOD_TILL_CANCEL) |
| 500 | 120009 | REJECTED:Request rejected by upstream service |
| 500 | 130008 | NON_APPLICABLE:Operation not applicable for current state |
### 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 |
### 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.
### Common Issues
#### TOO_MANY_REQUESTS After Websocket Connects
Websocket rate limits are pro-rated based on the calendar-second that the websocket connection was opened.
This means, depending on the fraction of the calendar-second that the connection was established, the rate limit could be pro-rated to a small number.
By adding a 1-second sleep after establishing the websocket connection, and before requests are sent, this will ensure the rate limit is properly reset and sync'd to your session.
This will avoid occurrences of rate-limit (TOO_MANY_REQUESTS) errors.
#### INVALID_NONCE On All Requests
The nonce should be the UTC Unix timestamp in milliseconds.
If this has been carefully checked, then the issue occurs when the system clock of the client machine is greater than 60 seconds in the future / past.
Usually, re-syncing with the NTP time server on the client machine will correct the issue.
If the issue persists, you can try deliberately subtracting N seconds from the nonce to force it to be N seconds in the past, which is still within the 60-second past tolerance.
---
## Crypto Wallet
Manages the user's wallet.
Most of the endpoints are only available at master account level.
Some endpoints requires Withdrawal setting to be enabled for your API Key. If you do not see the option when viewing your API Keys, this feature is not yet available for you.
---
## Fiat Wallet
Manages the user's fiat wallet.
Most of the endpoints are only available at master account level.
Some endpoints requires Withdrawal setting to be enabled for your API Key. If you do not see the option when viewing your API Keys, this feature is not yet available for you.
## Payment Networks and Currencies
This section provides a comprehensive reference table of all supported payment network and currency combinations available for use with the Fiat API endpoints. When making API calls to any of the Fiat service endpoints, use the payment network identifiers listed in this table for the payment_network or payment_networks parameters.
### Supported Payment Networks
| Payment Network | Currency |
|-----------------|----------|
| openpayd_exchange_sepa | EUR |
| usd_swift | USD |
| usd_fedwire | USD |
| usd_cubix | USD |
| uk_fps | GBP |
| aed_ipi | AED |
### Usage Notes
Activate the fiat service in your account before using the API. Go to Wallet page and select fiat currency to activate the fiat service. Bank account for USD need to be added in Crypto.com Wallet before using the API. For other currencies, bank account will be created after deposit. When calling Fiat API endpoints, you can specify payment networks in the following ways:
- Single Payment Network: `json { "payment_network": "usd_cubix" }`
- Multiple Payment Networks (comma-separated): `json { "payment_networks": "usd_cubix, usd_swift" }` Refer to the individual API endpoint documentation above for specific parameter requirements and usage examples.
---
## OTC RFQ for Taker
## RFQ Trading Flow
1. Taker can firstly subscribe to the following WebSocket channels:
- [`user.otc_qr.requests`](/docs/api/websocket/ws-channel-user-otc-qr-requests)
- [`user.otc_qr.quotes`](/docs/api/websocket/ws-channel-user-otc-qr-quotes)
- [`user.otc.deals`](/docs/api/websocket/ws-channel-user-otc-deals)
2. Taker can create a quote request via WebSocket: [`private/otc/request-quote`](/docs/api/websocket/ws-user-api-private-otc-request-quote-rfq)
3. Taker, who will be notified of quotes from the WebSocket channel [`user.otc_qr.quotes`](/docs/api/websocket/ws-channel-user-otc-qr-quotes), can create a deal request upon Quote message with [`private/otc/request-deal`](/docs/api/rest/private-otc-request-deal-rfq)
4. Taker will receive confirmation of the deal's status on WebSocket channel [`user.otc.deals`](/docs/api/websocket/ws-channel-user-otc-deals)
5. Taker can get the rejected or completed quote request from [Quote Query API](/docs/api/rest/private-otc-get-quote-request-history)
6. Taker can get the rejected or completed deal from [Deal Query API](/docs/api/rest/private-otc-get-deal-history-rfq)
## Quote Request Lifecycle
| Status | Description |
|--------|-------------|
| `ACTIVE` | user may receive a quote and user may call request-deal to execute a trade |
| `COMPLETED` | quote request duration has expired and no longer valid. User will not receive quote nor able to call request-deal anymore |
| `REJECTED` | rejected due to various reasons; quote request is no longer valid |
## Quote Lifecycle
| Status | Description |
|--------|-------------|
| `ACTIVE` | Quote is valid |
| `EXPIRED` | Quote has exceeded its TTL |
| `CANCELLED` | Liquidity provider cancelled the quote |
## Deal History
Use the deal history endpoint to retrieve executed trades. Deal statuses:
| Status | Description |
|--------|-------------|
| `ACCEPTED` | Deal request accepted by the system. |
| `CONFIRMED` | Liquidity provider has executed the deal. |
| `SETTLED` | Deal settled and funds transferred. |
| `REJECTED` | Deal request rejected (quote expired, insufficient balance, etc.) |
---
## private/advanced/amend-order
private/advanced/amend-order Amends an existing trigger order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the order is successfully amended.
**Trigger Order Type Conversion:**
- Set `new_price` to "0" → Convert trigger limit order to trigger market order
- Set `new_price` to "> 0" → Convert trigger market order to trigger limit order
## Request
---
## private/advanced/cancel-all-orders
private/advanced/cancel-all-orders Cancels all OTO/OTOCO orders for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advance.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/advanced/cancel-oco
private/advanced/cancel-oco Cancel an OCO order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
## Request
---
## private/advanced/cancel-order-list
private/advanced/cancel-order-list Cancels multiple advanced orders in a single request.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the orders are successfully canceled.
## Request
---
## private/advanced/cancel-order
private/advanced/cancel-order Cancel an individual order of a OTO/OTOCO order on the Exchange (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advance.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/advanced/cancel-oto
private/advanced/cancel-oto Cancel a SPOT_ATTACH or DERIV_ATTACH order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
**Note:** This API can also be used to cancel SpotAttach / DerivAttach orders regardless of the number of legs (2 or 3). Both `cancel-oto` and `cancel-otoco` can be used interchangeably to cancel SpotAttach / DerivAttach orders by `list_id`.
## Request
---
## private/advanced/cancel-otoco
private/advanced/cancel-otoco Cancel a SPOT_ATTACH or DERIV_ATTACH order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
**Note:** This API can also be used to cancel SpotAttach / DerivAttach orders regardless of the number of legs (2 or 3). Both `cancel-oto` and `cancel-otoco` can be used interchangeably to cancel SpotAttach / DerivAttach orders by `list_id`.
## Request
---
## private/advanced/create-oco
private/advanced/create-oco Creates a One-cancels-the-Other (OCO) execution strategy on the Exchange.
OCO execution strategy allows users to place a two-order strategy where one order automatically cancels the other when one of the orders is partially/fully executed. Users are able to place 2 orders - one LIMIT and one trigger order. Only one of the orders will be executed. The trigger order can either be a stop loss or take profit order. The OCO order type is only available for Spot trading pairs for now.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT`, the other order must be `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT` or `TAKE_PROFIT`. For `ref_price_type` of the trigger order, only `MARK_PRICE` is supported for now.
## Request
---
## private/advanced/create-order-list
private/advanced/create-order-list Creates multiple advanced orders in a single request.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the orders are successfully created.
## Request
---
## private/advanced/create-order
private/advanced/create-order Creates a new BUY or SELL trigger order on the Exchange.
`type` must be STOP_LOSS, STOP_LIMIT, TAKE_PROFIT or TAKE_PROFIT_LIMIT.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check if the orders are successfully created.
**Helpful information:**
- STOP_LIMIT and TAKE_PROFIT_LIMIT will execute a LIMIT order when the ref_price is reached.
- STOP_LOSS and TAKE_PROFIT will execute a MARKET order when the ref_price is reached.
**To create trigger orders based on ref_price vs. the reference price (ref_price_type):**
- ref_price below ref_price_type price: SELL STOP_LOSS and STOP_LIMIT, BUY TAKE_PROFIT and TAKE_PROFIT_LIMIT
- ref_price above ref_price_type price: BUY STOP_LOSS and STOP_LIMIT, SELL TAKE_PROFIT and TAKE_PROFIT_LIMIT
**SpotAttach / DerivAttach:**
- **Contingency type resolution**: Automatically resolved from instrument type - spot instruments → SPOT_ATTACH, derivative instruments → DERIV_ATTACH
- **DerivAttach attach-to-order**: Use `attach_order_id` to attach TP/SL to an existing limit order
- **DerivAttach attach-to-position**: Use `attach_isolation_id` to attach TP/SL directly to an existing position (\> 0 for isolated position ID, 0 for cross-margin position). Requires REDUCE_ONLY in exec_inst.
- **Standalone TP/SL**: For derivatives, if neither `attach_order_id` nor `attach_isolation_id` is specified, isolation is resolved from `isolation_id` parameter (if provided) or defaults to cross-margin
## Request
---
## private/advanced/create-oto
private/advanced/create-oto Creates a One-triggers-the-Other (OTO) execution strategy on the Exchange.
OTO execution strategy allows users to place a two-order strategy where one order automatically triggers the other when the first order is fully executed. Users are able to place a limit or market order with a trigger order, and only when the primary order is fully executed, the trigger order will take effect. The trigger order can either be a stop loss or take profit order.
**SpotAttach / DerivAttach:** This API creates SpotAttach (for spot instruments) or DerivAttach (for derivative instruments) order types. The contingency type is automatically resolved from the instrument type. With 2 legs (1 limit/market + 1 trigger), it follows OTO behavior.
- **SpotAttach**: Flexible - you can later attach additional TP/SL using `private/advanced/create-order` with `attach_order_id`, effectively converting it to OTOCO behavior. You can also cancel individual legs using `private/advanced/cancel-order` and reattach new ones.
- **DerivAttach**: For derivatives, the primary leg may specify `isolation_id`, `leverage`, `isolated_margin_amount`, and `exec_inst` may include ISOLATED_MARGIN. Trigger legs inherit the isolation mode from the parent leg.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT` or `MARKET`, and the other must be `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT` or `TAKE_PROFIT`. The `ref_price_type` for the trigger order supports `MARK_PRICE` (default), `INDEX_PRICE`, and `LAST_PRICE`.
## Request
---
## private/advanced/create-otoco
private/advanced/create-otoco Creates a One-Triggers-a-One-Cancels-the-Other (OTOCO) execution strategy on the Exchange.
OTOCO execution strategy allows users to place a three-order strategy where one order automatically triggers the other two when the first order is fully executed. Users are able to place a limit or market order with two trigger orders, and only when the primary order is fully executed, the two trigger orders will take effect. The two trigger orders must be one stop loss and one take profit orders.
**SpotAttach / DerivAttach:** This API creates SpotAttach (for spot instruments) or DerivAttach (for derivative instruments) order types. The contingency type is automatically resolved from the instrument type. With 3 legs (1 limit/market + 2 triggers), it follows OTOCO behavior.
- **SpotAttach**: When either one of the two trigger orders is executed, the other is automatically canceled (OCO behavior). SpotAttach orders are flexible - you can cancel one of the TP/SL legs using `private/advanced/cancel-order`, effectively converting it to OTO behavior. You can also reattach new TP/SL using `private/advanced/create-order` with `attach_order_id`.
- **DerivAttach**: For derivatives, the two trigger legs are independent - one firing does NOT cancel the other (unlike SpotAttach). The primary leg may specify `isolation_id`, `leverage`, `isolated_margin_amount`, and `exec_inst` may include ISOLATED_MARGIN. Trigger legs inherit the isolation mode from the parent leg.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT` or `MARKET`, and for the two trigger orders, one must be `STOP_LOSS` or `STOP_LIMIT`, and the other one must be `TAKE_PROFIT` or `TAKE_PROFIT_LIMIT`. The `ref_price_type` for the trigger orders supports `MARK_PRICE` (default), `INDEX_PRICE`, and `LAST_PRICE`.
## Request
---
## private/advanced/get-open-orders
private/advanced/get-open-orders Gets all open orders for OTO/OTOCO orders for a particular instrument.
## Request
---
## private/advanced/get-order-detail
private/advanced/get-order-detail Gets detail of a single advanced order by `order_id` or `client_oid`.
## Request
---
## private/advanced/get-order-history
private/advanced/get-order-history Gets the order history of OTO/OTOCO orders for a particular instrument.
Users should use `user.advance.order` to keep track of real-time order updates, and `private/advanced/get-order-history` should primarily be used for recovery; typically when the websocket is disconnected.
## Request
---
## private/advanced/get-order-list-detail
private/advanced/get-order-list-detail Gets order details for multiple OCO/SpotAttach orders by their list IDs.
This endpoint allows batch querying of order information across different contingency order groups.
## Request
---
## private/amend-order
private/amend-order Amend an existing order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The user.order subscription can be used to check when the order is successfully created.
Please note that amend order is designed as a convenience function such that it performs cancel and then create behind the scene. The new order will lose queue priority, except if the amend is only to amend down order quantity.
## Request
---
## private/bot/create-trading-bot (DCA)
private/bot/create-trading-bot (DCA) Creates a new DCA (Dollar-Cost Averaging) Trading Bot that automatically buys or sells at regular intervals over a preset time frame.
DCA trading is used by investors who would like to reduce the influence of volatility and accumulate or decumulate positions gradually.
## Request
---
## private/bot/create-trading-bot (FUNDING_ARBITRAGE)
private/bot/create-trading-bot (FUNDING_ARBITRAGE) Creates a new Funding Arbitrage Trading Bot that simultaneously holds a spot position and an opposing perpetual swap position to capture funding rate income.
## Request
---
## private/bot/create-trading-bot (GRID)
private/bot/create-trading-bot (GRID) Creates a new GRID Trading Bot that automatically places buy and sell orders within a defined price range.
## Request
---
## private/bot/create-trading-bot (TWAP)
private/bot/create-trading-bot (TWAP) Creates a new TWAP (Time-Weighted Average Price) Trading Bot that executes large orders by splitting them into smaller slices over a defined time window to minimise market impact.
## Request
---
## private/bot/get-trading-bot-executions
private/bot/get-trading-bot-executions Returns the order execution history for a specific Trading Bot.
## Request
---
## private/bot/get-trading-bots
private/bot/get-trading-bots Returns a list of Trading Bots filtered by type and state. Results are sorted by update time in descending order.
## Request
---
## private/bot/pause-trading-bot
private/bot/pause-trading-bot Pauses a running Trading Bot. The bot's open orders are cancelled and no new orders will be placed until resumed.
## Request
---
## private/bot/resume-trading-bot
private/bot/resume-trading-bot Resumes a paused Trading Bot. The bot will restart placing orders according to its configured strategy.
## Request
---
## private/bot/terminate-trading-bot
private/bot/terminate-trading-bot Terminates a Trading Bot. All open orders placed by the bot are cancelled.
## Request
---
## private/bot/update-trading-bot (DCA)
private/bot/update-trading-bot (DCA) Updates settings for a running or paused DCA (Dollar-Cost Averaging) Trading Bot.
Updatable settings for DCA bots include allocations, order type, price, max_order, stop/take-profit prices, auto_stake, investment parameters, and quantity.
## Request
---
## private/bot/update-trading-bot (FUNDING_ARBITRAGE)
private/bot/update-trading-bot (FUNDING_ARBITRAGE) Updates a Funding Arbitrage Trading Bot.
Note: Funding Arbitrage bots do not support updating settings. Only `display_name` and `notify_on_bot_change` can be changed.
## Request
---
## private/bot/update-trading-bot (GRID)
private/bot/update-trading-bot (GRID) Updates settings for a running or paused GRID Trading Bot.
Updatable settings for GRID bots include stop_price, take_profit_price, and trailing_up_price_cap.
## Request
---
## private/bot/update-trading-bot (TWAP)
private/bot/update-trading-bot (TWAP) Updates a TWAP (Time-Weighted Average Price) Trading Bot.
Note: TWAP bots do not support updating settings. Only `display_name` and `notify_on_bot_change` can be changed.
## Request
---
## private/cancel-all-orders
private/cancel-all-orders Cancels all orders for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/cancel-order-list (LIST)
private/cancel-order-list (LIST) Cancel a list of orders on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when each of the orders is successfully cancelled.
## Request
---
## private/cancel-order
private/cancel-order Cancels an existing order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/change-account-leverage
private/change-account-leverage Changes the maximum leverage used by the account. Please note, each instrument has its own maximum leverage. Whichever leverage (account or instrument) is lower will be used.
## Request
---
## private/change-account-settings
private/change-account-settings Change account level settings regarding STP and other properties.
## Request
---
## private/change-isolated-margin-leverage
private/change-isolated-margin-leverage Changes the maximum leverage of an isolated position.
## Request
---
## private/close-position
private/close-position Cancels position for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/create-isolated-margin-transfer
private/create-isolated-margin-transfer Transfer balance between account and isolated position.
## Request
---
## private/create-order
private/create-order Creates a new BUY or SELL order.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully created.
## Request
---
## private/create-order-list (LIST)
private/create-order-list (LIST) Create a list of orders on the Exchange.
`contingency_type` must be LIST, for list of orders creation.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check if the orders are successfully created.
## Request
---
## private/create-subaccount-transfer
private/create-subaccount-transfer Transfer between subaccounts (and master account).
## Request
---
## private/create-withdrawal
private/create-withdrawal Creates a withdrawal request. Withdrawal setting must be enabled for your API Key. If you do not see the option when viewing your API Key, this feature is not yet available for you.
## Request
---
## private/fiat/fiat-access
private/fiat/fiat-access Retrieves fiat access information for a user account. Used by FCM/DCM brokers to check deposit and withdrawal permissions for different currencies and payment networks on behalf of their users.
## Request
---
## private/fiat/fiat-create-bank-account
private/fiat/fiat-create-bank-account Link a bank account via Plaid for a user. Links the user's bank account to their profile for withdrawals using a Plaid integration payload.
## Request
---
## private/fiat/fiat-create-withdraw
private/fiat/fiat-create-withdraw Creates a new fiat withdrawal request for the authenticated user.
## Request
---
## private/fiat/fiat-deposit-history
private/fiat/fiat-deposit-history Retrieves paginated fiat deposit transaction history for the authenticated user.
## Request
---
## private/fiat/fiat-deposit-info
private/fiat/fiat-deposit-info Retrieves fiat deposit information for the authenticated user. Returns bank details for depositing fiat currency with optional payment network filtering.
## Request
---
## private/fiat/fiat-get-bank-accounts
private/fiat/fiat-get-bank-accounts Retrieves user's bank accounts with optional payment network filtering.
## Request
---
## private/fiat/fiat-transaction-limit
private/fiat/fiat-transaction-limit Retrieves transaction limits for a specific payment network.
## Request
---
## private/fiat/fiat-transaction-quota
private/fiat/fiat-transaction-quota Retrieves transaction quota information for a specific payment network.
## Request
---
## private/fiat/fiat-withdraw-history
private/fiat/fiat-withdraw-history Retrieves paginated fiat withdrawal transaction history for the authenticated user.
## Request
---
## private/get-account-settings
private/get-account-settings Get account settings.
## Request
---
## private/get-accounts
private/get-accounts Get Account and its Sub Accounts.
## Request
---
## private/get-currency-networks
private/get-currency-networks Get the symbol network mapping.
## Request
---
## private/get-deposit-address
private/get-deposit-address Fetches deposit address. Withdrawal setting must be enabled for your API Key. If you do not see the option when viewing your API Keys, this feature is not yet available for you.
## Request
---
## private/get-deposit-history
private/get-deposit-history Fetches deposit history. If you do not see the option when viewing your API Keys, this feature is not yet available for you.
## Request
---
## private/get-fee-credit-balances
private/get-fee-credit-balances Get fee credit balance details for the authenticated account. Fee credits are grouped by expiry date and sorted in ascending order. Values are not real-time and are updated daily at 00:00 UTC.
## Request
---
## private/get-fee-rate
private/get-fee-rate Get fee rates for user’s account.
## Request
---
## private/get-instrument-fee-rate
private/get-instrument-fee-rate Get the instrument fee rate.
## Request
---
## private/get-open-orders
private/get-open-orders Gets all open orders for a particular instrument.
## Request
---
## private/get-order-detail
private/get-order-detail Gets detail of a single order by order_id or client_oid.
## Request
---
## private/get-order-history
private/get-order-history Gets the order history for a particular instrument.
Users should use `user.order` to keep track of real-time order updates, and `private/get-order-history` should primarily be used for recovery; typically when the websocket is disconnected.
## Request
---
## private/get-positions
private/get-positions Returns the user's position.
## Request
---
## private/get-subaccount-balances
private/get-subaccount-balances Returns the user's wallet balances of all sub-accounts.
## Request
---
## private/get-trades
private/get-trades Gets all executed trades for a particular instrument.
Users should use `user.trade` to keep track of real-time trades, and `private/get-trades` should primarily be used for recovery; typically when the websocket is disconnected.
## Request
---
## private/get-transactions
private/get-transactions Fetches recent transactions.
## Request
---
## private/get-withdrawal-addresses
private/get-withdrawal-addresses Lists the caller's saved (whitelisted) withdrawal addresses. Returns only active addresses, newest first. Filter by `currency`, `network_id`, or both; an unknown value returns an empty list rather than an error.
## Request
---
## private/get-withdrawal-history
private/get-withdrawal-history Fetches withdrawal history. If you do not see the option when viewing your API Keys, this feature is not yet available for you.
## Request
---
## private/otc/get-deal-history (RFQ)
private/otc/get-deal-history (RFQ) Get closed deals for given user.
## Request
---
## private/otc/get-open-deals (RFQ)
private/otc/get-open-deals (RFQ) Get quote requests history. Only return closed quote requests (status = COMPLETED/REJECTED).
## Request
---
## private/otc/get-open-quote-requests
private/otc/get-open-quote-requests Get open quote requests. Only return active quote requests (status = NEW or ACTIVE).
## Request
---
## private/otc/get-open-quotes
private/otc/get-open-quotes Get open quotes. Only return active Quotes (status = ACTIVE).
## Request
---
## private/otc/get-otc-instruments
private/otc/get-otc-instruments Retrieves a list of available OTC instruments that takers can request quotes for.
## Request
---
## private/otc/get-quote-history
private/otc/get-quote-history Get quotes history.
## Request
---
## private/otc/get-quote-request-history
private/otc/get-quote-request-history Get quote requests history. Only return closed quote requests (status = COMPLETED/REJECTED).
## Request
---
## private/otc/get-settle-later-limit
private/otc/get-settle-later-limit Get used settle later limit as well as the configured limit for account.
## Request
---
## private/otc/get-unsettled-amounts
private/otc/get-unsettled-amounts Get pending settlement amount aggregated by date and instrument.
## Request
---
## private/otc/request-deal (RFQ)
private/otc/request-deal (RFQ) Request a deal from a quote (RFQ flow).
## Request
---
## private/otc/request-quote (RFQ)
private/otc/request-quote (RFQ) Create a quote request (RFQ flow).
## Request
---
## private/staking/convert
private/staking/convert Create a request to convert between staked token with liquid staking token.
## Request
---
## private/staking/get-convert-history
private/staking/get-convert-history Get convert request history
## Request
---
## private/staking/get-open-convert
private/staking/get-open-convert Get convert request that status is not in final state.
## Request
---
## private/staking/get-open-stake
private/staking/get-open-stake Get stake/unstake requests that status is not in final state.
## Request
---
## private/staking/get-reward-history
private/staking/get-reward-history Get stake/unstake request history
## Request
---
## private/staking/get-stake-history
private/staking/get-stake-history Get stake/unstake request history
## Request
---
## private/staking/get-staking-instruments
private/staking/get-staking-instruments Get staking instruments information
## Request
---
## private/staking/get-staking-position
private/staking/get-staking-position Get the total staking position for a user/token
## Request
---
## private/staking/stake
private/staking/stake Create a request to earn token rewards by staking on-chain in the Exchange.
## Request
---
## private/staking/unstake
private/staking/unstake Create a request to unlock staked token.
## Request
---
## private/user-balance-history
private/user-balance-history Returns the user's balance history. This call may temporarily have discrepancies with that shown on the GUI.
## Request
---
## private/user-balance
private/user-balance Returns the user's wallet balance.
## Request
---
## public/get-book
public/get-book Fetches the public order book for a particular instrument and depth.
## Request
Query Parameters
---
## public/get-candlestick
public/get-candlestick Retrieves candlesticks (k-line data history) over a given period for an instrument (e.g. BTCUSD-PERP).
## Request
Query Parameters
---
## public/get-deposit-instruments
public/get-deposit-instruments Returns the list of instruments eligible for deposit and use as collateral.
---
## public/get-expired-settlement-price
public/get-expired-settlement-price Fetches settlement prices of expired instruments.
## Request
Query Parameters
---
## public/get-instruments
public/get-instruments Provides information on all supported instruments (e.g. BTCUSD-PERP).
## Request
Query Parameters
---
## public/get-insurance
public/get-insurance Fetches the balance of the Insurance Fund for a particular currency.
## Request
Query Parameters
---
## public/get-risk-parameters
public/get-risk-parameters Provides information on risk parameter settings for [Smart Cross Margin](https://crypto.com/exchange/document/margin-rules).
---
## public/get-tickers
public/get-tickers Fetches the public tickers for all or a particular instrument.
## Request
Query Parameters
---
## public/get-trades
public/get-trades Fetches the public trades for a particular instrument. Time window can only be up to 7 days for maximum.
## Request
Query Parameters
---
## public/get-valuations
public/get-valuations Fetches valuation type data for an instrument.
## Request
Query Parameters
---
## public/staking/get-conversion-rate
public/staking/get-conversion-rate Returns conversion rate between staked token (e.g. ETH.staked) and liquid staking token (e.g. CDCETH). Params instrument_name (e.g. CDCETH). Used before private/staking/convert.
## Request
---
## Reference and Market Data
Reference and market data endpoints provide public, unauthenticated access to instrument metadata, real-time market data, and historical pricing information. These endpoints form the foundation for price discovery, order book analysis, and trading decision workflows.
## Core Data Types
### Instrument Reference Data
Use [`public/get-instruments`](/docs/api/rest/public-get-instruments) to retrieve the full catalog of tradable instruments. Each instrument includes:
- Contract specifications (tick size, quantity decimals, leverage limits)
- Product classification (perpetual swap, future, option)
- Trading status and expiry information
- Underlying index reference
This endpoint should be called on application startup and periodically refreshed to detect new listings or contract expirations.
### Real-Time Market Data
| Endpoint | Use Case | Update Frequency |
|----------|----------|------------------|
| [`public/get-book`](/docs/api/rest/public-get-book) | Order book depth (bids/asks) | Snapshot on request (up to 50 levels) |
| [`public/get-tickers`](/docs/api/rest/public-get-tickers) | 24h summary (high, low, volume, open interest) | Updated per trade |
| [`public/get-trades`](/docs/api/rest/public-get-trades) | Recent trade history | Last 150 trades (7-day max window) |
For low-latency applications, use WebSocket subscriptions instead:
- `book.{instrument_name}.{depth}` - Order book updates (10 or 50 levels)
- `ticker.{instrument_name}` - Real-time ticker updates
- `trade.{instrument_name}` - Trade feed
### Settlement and Expiry
[`public/get-expired-settlement-price`](/docs/api/rest/public-get-expired-settlement-price) provides historical settlement prices for expired futures contracts. Use this for post-trade reconciliation and historical PnL calculations.
## Rate Limits
Public endpoints share a global rate limit pool. For market data-intensive applications:
- Use WebSocket subscriptions instead of polling REST endpoints
- Cache `public/get-instruments` responses (updates infrequently)
- Batch ticker requests by omitting `instrument_name` to get all tickers in one call
## Typical Integration Flow
**Step 1 — Bootstrap Reference Data**
Call `public/get-instruments` to load the instrument catalog. Store contract specifications locally.
**Step 2 — Subscribe to Market Data**
For real-time pricing, establish WebSocket connections and subscribe to:
- `book.{instrument_name}.10` - top 10 order book levels
- `ticker.{instrument_name}` - 24h summary stats
- `trade.{instrument_name}` - trade feed
**Step 3 — Polling Fallback**
If WebSocket connections are unavailable, poll `public/get-tickers` and `public/get-book` at reasonable intervals (e.g., 1-5 seconds).
---
## Staking
Stake crypto assets on-chain to earn rewards directly from the Exchange. Staking locks your tokens for a period, during which you earn periodic rewards. Liquid staking tokens (e.g., CDCETH) allow you to maintain liquidity while staking.
## Staking Workflow
**1. Check Available Instruments**
Call [`private/staking/get-staking-instruments`](/docs/api/rest/private-staking-get-staking-instruments) to retrieve the list of tokens available for staking, including minimum stake amounts and reward rates.
**2. Stake Tokens**
Call [`private/staking/stake`](/docs/api/rest/private-staking-stake) to lock tokens and begin earning rewards. The request is processed asynchronously.
**3. Monitor Position**
Use [`private/staking/get-staking-position`](/docs/api/rest/private-staking-get-staking-position) to view your total staked balance and [`private/staking/get-open-stake`](/docs/api/rest/private-staking-get-open-stake) to track pending stake requests.
**4. Unstake Tokens**
Call [`private/staking/unstake`](/docs/api/rest/private-staking-unstake) to unlock staked tokens. Unstaking may involve a waiting period depending on the underlying blockchain protocol.
## Liquid Staking
Liquid staking tokens (e.g., CDCETH for staked ETH) represent staked assets and can be traded or held. Use the conversion endpoints to move between staked tokens and liquid staking tokens:
- [`public/staking/get-conversion-rate`](/docs/api/rest/public-staking-get-conversion-rate) — get the current conversion rate
- [`private/staking/convert`](/docs/api/rest/private-staking-convert) — convert between staked and liquid staking tokens
- [`private/staking/get-open-convert`](/docs/api/rest/private-staking-get-open-convert) — track pending conversion requests
## History
| Endpoint | Description |
|----------|-------------|
| [`private/staking/get-stake-history`](/docs/api/rest/private-staking-get-stake-history) | Past stake and unstake requests |
| [`private/staking/get-reward-history`](/docs/api/rest/private-staking-get-reward-history) | Earned staking rewards |
| [`private/staking/get-convert-history`](/docs/api/rest/private-staking-get-convert-history) | Past conversion requests |
---
## Trading Bot API
Manage automated trading bots including DCA (Dollar-Cost Averaging), TWAP (Time-Weighted Average Price), GRID, and Funding Arbitrage strategies.
## Bot Types
| Type | Description |
|------|-------------|
| DCA | Dollar-Cost Averaging - automatically buys or sells at regular intervals over a preset time frame |
| TWAP | Time-Weighted Average Price - executes large orders by splitting them into smaller slices over a defined time window |
| GRID | Grid Trading - automatically places buy and sell orders within a defined price range |
| FUNDING_ARBITRAGE | Funding Arbitrage - simultaneously holds a spot position and an opposing perpetual swap position to capture funding rate income |
## Bot States
| State | Description |
|-------|-------------|
| RUNNING | Bot is actively placing orders |
| PAUSED | Bot is paused, no new orders will be placed |
| TERMINATED | Bot has been terminated |
---
## Trading
Private trading endpoints manage order placement and lifecycle. All order operations (create, amend, cancel) are asynchronous — the REST response confirms the request was received, but order lifecycle updates arrive via WebSocket subscriptions.
## Order Management Workflow
**Create Order**
Call `private/create-order` to submit a new order. The response returns an `order_id` and `client_oid`, but the order may still be pending acceptance by the matching engine. Subscribe to `user.order` or `user.order.{instrument_name}` to receive real-time order status updates.
**Amend Order**
Call [`private/amend-order`](/docs/api/rest/private-amend-order) to modify price or quantity on an existing order. Behind the scenes, amend performs a cancel-then-create operation. The new order loses queue priority unless you are only reducing quantity.
**Cancel Order**
Call [`private/cancel-order`](/docs/api/rest/private-cancel-order) to cancel a single order by `order_id` or `client_oid`, or [`private/cancel-all-orders`](/docs/api/rest/private-cancel-all-orders) to cancel all orders for a given instrument.
## Order Types
| Type | Description |
|------|-------------|
| `LIMIT` | Limit order with specified price. Rests on the order book until filled or canceled. |
| `MARKET` | Market order that executes immediately at best available price. |
For trigger orders (stop-loss, take-profit) and multi-leg strategies (OCO, OTO, OTOCO), see [Advanced Order Management](/docs/api/rest/advanced-order-management).
## Time in Force
| Value | Description |
|-------|-------------|
| `GOOD_TILL_CANCEL` | Order remains active until filled or explicitly canceled. Default for limit orders. |
| `IMMEDIATE_OR_CANCEL` | Order fills immediately (partial or full), unfilled portion is canceled. |
| `FILL_OR_KILL` | Order must fill entirely and immediately, or the entire order is canceled. |
## Execution Instructions
Execution instructions are passed as an array in `exec_inst`. Multiple instructions can be combined.
| Instruction | Description |
|-------------|-------------|
| `POST_ONLY` | Order is rejected if it would take liquidity. Ensures maker fee. |
| `SMART_POST_ONLY` | If the order would take liquidity, it is repriced to the best maker level instead of being rejected. |
| `REDUCE_ONLY` | Order can only reduce an existing position, not increase or open a new position. |
## Order Statuses
| Status | Description |
|--------|-------------|
| `PENDING` | Order submitted, awaiting processing by the matching engine. |
| `NEW` | Order accepted by the matching engine, not yet on the order book. |
| `ACTIVE` | Order is live on the order book, waiting to be filled. |
| `FILLED` | Order has been completely filled. |
| `CANCELED` | Order was canceled (by user request, or by system). |
| `EXPIRED` | Order expired due to time-in-force constraints. |
| `REJECTED` | Order was rejected (e.g., invalid parameters, risk checks failed). |
## Querying Orders and Trades
- [`private/get-open-orders`](/docs/api/rest/private-get-open-orders) — retrieve all currently active orders
- [`private/get-order-detail`](/docs/api/rest/private-get-order-detail) — fetch detailed information about a single order
- [`private/get-order-history`](/docs/api/rest/private-get-order-history) — retrieve past orders (filled, canceled, or rejected)
- [`private/get-trades`](/docs/api/rest/private-get-trades) — retrieve executed trades (fills)
## Real-Time Order and Trade Updates
Subscribe to the following WebSocket channels for real-time updates:
| Channel | Description |
|---------|-------------|
| `user.order` | Order lifecycle events across all instruments |
| `user.order.{instrument_name}` | Order updates for a specific instrument |
| `user.trade` | Trade execution events across all instruments |
| `user.trade.{instrument_name}` | Trade execution events for a specific instrument |
These subscriptions require authentication and eliminate the need for polling REST endpoints.
---
## Transaction History
History will be stored for recent 6 months record only. For records over 6 months, please contact our support team.
---
## Breaking Change Schedule
- On 2025-12-17 8:00 UTC,
The current trigger order creation/cancellation will be migrated to Advanced Order Management API.
- On 2025-02-27 8:00 UTC,
For `book.{instrument_name}.{depth}`, the full snapshot subscription (`book_subscription_type=SNAPSHOT`) `100ms` frequency is removed.
Customers wishing to continue with the faster `100ms` frequency should switch to the delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`).
This higher performing subscription benefits the user with reduced bandwidth/processing compared to the snapshot subscription.
For a transition period, users subscribing to the removed `100ms` snapshot will receive the `500ms` subscription.
The `book.{instrument_name}` subscription (default depth) will be removed.
Customers should use the explicit `book.{instrument_name}.{depth}` subscription and specify the required depth.
For a transition period, users subscribing to the removed subscription will receive the default `50` depth subscription.
- These changes will take place around 17 December 2023 8:00 UTC.
- Market Data wildcard ticker subscription will be removed. Users should use the instrument specific subscription.
---
## Change Log(Api)
- **2026-05-21**
- `public/get-instruments` response updated, new field `product_type` was added
- Trading Bot API section was added:
`private/bot/create-trading-bot` (DCA, TWAP, GRID, FUNDING_ARBITRAGE)
`private/bot/terminate-trading-bot`
`private/bot/update-trading-bot`
`private/bot/pause-trading-bot`
`private/bot/resume-trading-bot`
`private/bot/get-trading-bots`
`private/bot/get-trading-bot-executions`
- **2026-05-07**
- Advanced Order Management API section was updated for DerivAttach
- `private/advanced/create-oto` and `private/advanced/create-otoco` — contingency type is now resolved from instrument type: spot instruments create SPOT_ATTACH, derivative instruments create DERIV_ATTACH. DerivAttach supports `isolation_id`, `leverage`, `isolated_margin_amount` on the primary leg and `ISOLATED_MARGIN` in `exec_inst`. Trigger legs inherit isolation mode from the parent.
- `private/advanced/create-order` — `attach_order_id` now applies to both SpotAttach and DerivAttach. New optional field `attach_isolation_id` for DerivAttach attach-to-position (derivatives only).
- `private/advanced/cancel-oto` and `private/advanced/cancel-otoco` — updated to cover both SPOT_ATTACH and DERIV_ATTACH.
- `private/advanced/cancel-all-orders` — new optional field `position_type` (CROSS_MARGIN, ISOLATED_MARGIN).
- `private/advanced/get-open-orders`, `private/advanced/get-order-detail`, `private/advanced/get-order-history`, and `user.advance.order` — response attributes extended with `exchange_order_id`, `ref_price`, `ref_price_type`, `reject_reason`, `attach_isolation_id`, `isolation_id`, `isolation_type`, `leverage`, `isolated_margin_amount`. `contingency_type` now includes DERIV_ATTACH.
- `private/advanced/amend-order` — corrected required/optional flags: `new_price` is Y, `new_quantity` is Y, `new_ref_price` is N.
- **2026-04-29**
- Fee Credits
- `private/get-fee-credit-balances` was added
- `private/get-trades` response updated, new field `fee_credits` was added
- `user.trade.{instrument_name}` response updated, new field `fee_credits` was added
- **2026-04-07**
- `private/get-accounts` response updated, new field `hierarchy` was added
- **2026-04-01**
- `private/create-order` request updated, `REDUCE_ONLY` was added to `exec_inst`
- **2026-01-08**
- Add support for isolated position
- `private/create-isolated-margin-transfer` was added
- `private/change-isolated-margin-leverage` was added
- `private/user-balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/user-balance-history` response updated, new field `i` was added
- `private/get-subaccount-balances` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/get-positions` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/create-order` request updated, new optional fields `isolation_id`, `leverage`, `isolated_margin_amount` were added, `exec_inst` added support for `ISOALTED_MARGIN`
- `private/close-position` request updated, new optional field `isolation_id` was added
- `private/get-open-orders` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-detail` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-history` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-trades` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-transactions` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `user.order.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.trade.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `user.positions` response updated, new fields `isolation_id`, `leverage`, `isolation_type`, `liquidation_price` and `isolated_margin_balance` were added
- `user.account_risk` response updated, new fields `total_isolated_cash_balance`, `isolated_positions` were added
- `user.position_balance` response updated, new field `isolated_positions` was added
- **2025-03-26**
- `transaction_time` was added into `user.order.{instrument_name}`
- **2025-11-18**
- `public/get-risk-parameters` was added new columns
- **2025-10-16**
- `Advanced Order Management API` section was updated
- **2025-07-17**
- `private/fiat/fiat-deposit-info` was added
- `private/fiat/fiat-deposit-history` was added
- `private/fiat/fiat-withdraw-history` was added
- `private/fiat/fiat-create-withdraw` was added
- `private/fiat/fiat-get-bank-accounts` was added
- `private/fiat/fiat-transaction-quota` was added
- `private/fiat/fiat-transaction-limit` was added
- **2025-07-04**
- `private/create-order` exec_inst was added `SMART_POST_ONLY`
- `private/create-order-list (LIST)` exec_inst was added `SMART_POST_ONLY`
- `private/get-open-orders` exec_inst was added `SMART_POST_ONLY`
- `private/get-order-detail` was added, exec_inst was added `SMART_POST_ONLY`
- `private/get-order-history` exec_inst was added `SMART_POST_ONLY`
- **2025-06-10**
- `private/amend-order` was added
- `public/get-announcements` was added
- **2025-05-29**
- transaction_time_ns field was added into `user.order.{instrument_name}` response
- **2025-03-14**
- Removed deprecated attributes system_label in `private/get-accounts`
- **2025-03-06**
- Removed deprecated `book.{instrument_name}` default book subscription
- Removed deprecated 100ms interval from full snapshot `book.{instrument_name}.{depth}` book subscription
- **2025-03-04**
- Remove section: `Unified Wallet and System Label`
- **2025-01-27**
- `book.{instrument_name}.{depth}` - The following additional update frequencies are now supported:
Full snapshot subscription (`book_subscription_type=SNAPSHOT`) `500ms`
Delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`) `100ms`
- **2024-12-11**
- `private/create-order` fee_instrument_name was added
- **2024-10-02**
- `public/get-risk-parameters` was added
- **2024-08-15**
- `private/get-fee-rate` was added
- `private/get-instrument-fee-rate` was added
- **2024-07-12**
- Staking API added:
`private/staking/stake`
`private/staking/unstake`
`private/staking/get-staking-position`
`private/staking/get-staking-instruments`
`private/staking/get-open-stake`
`private/staking/get-stake-history`
`private/staking/get-reward-history`
`private/staking/convert`
`private/staking/get-open-convert`
`private/staking/get-convert-history`
`public/staking/get-conversion-rate`
- **2024-06-27**
- `private/create-order` self-trade prevent (STP) was added
- `private/create-order-list (LIST)` self-trade prevent (STP) was added
- **2024-02-12**
- `public/get-trades`, `trade.{instrument_name}` subscription, clarification for the public trade side field
- Side is the side of the taker order
- `book.{instrument_name}.{depth}` clarifications for book delta sequence number handling and re-subscription
- **2024-01-04**
- Market data websocket subscription enhancements:
- `book.{instrument_name}` - The `subscription` result value is now explicit
e.g. previous `"subscription": "book.BTC_USD"` -> new `"subscription": "book.BTC_USD.50"`
- `book.{instrument_name}.{depth}` - For delta updates, the fixed 500ms delta full book snapshot heartbeat is replaced with empty delta in the case of no book changes
- `ticker` - Documented existing 'bs' and 'ks' fields (bid/ask size)
- `settlement` - For wildcard subscription, the `subscription` result value is now explicit
e.g. previous `"subscription": "settlement"` -> new `"subscription": "settlement.BTCUSD-231124"`
- Applied consistent field ordering for all market data subscriptions (`book`, `ticker`, `trade`, `candlestick`, `index`, `mark`, `settlement`, `funding`, `estimatedfunding`).
Result fields are always in the following order:
`id, method, code, instrument_name, subscription, channel`
- Market data REST `public/get-trades`
- Added additional `tn` nanoseconds timestamp field to the trade response
- Clarified timestamp pagination parameters
- **2023-12-18**
- Market Data wildcard ticker subscription removed. Users should use the instrument specific subscription.
- **2023-12-11**
- Introduced Market Data subscription limiting. Refer to Market Data Websocket Subscription Limits for more details
- **2023-10-31**
- `user.balance`, `private/user-balance` will be updated:
1. Existing field total_margin_balance will represent new margin balance calculation without haircut.
2. Existing field total_initial_margin previously is made up of position IM only. On effective date, this field will represent the total sum of total_position_im + total_haircut
3. New field total_position_im will be introduced to represent initial margin requirement to support open positions and orders
4. New field total_haircut will be introduced to represent the total haircut on eligible collateral token assets. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- `user.balance`, `user.account_risk`, `private/user-balance`, `private/get-subaccount-balances` will be updated:
1. New field collateral_eligible will be introduced to indicate if token is eligible Collateral
2. collateral_weight will be deprecated
3. New field haircut will be introduced to show haircut of eligible collateral token instead of collateral Weight. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- **2023-08-11**
- `private/create-order-list (LIST)` for batch order creation added
- `private/cancel-order-list (LIST)` for batch order cancel added
- **2023-07-31**
- Market Data Websocket Subscriptions is effective:
- `funding.{instrument_name}` - channel will return the fixed hourly rate that will settle at the end of the hour.
- `estimatedfunding.{instrument_name}` - channel will return the estimated hourly rate that will begin in the next interval.
- Added new "funding_rate" and "estimated_funding_rate" valuation types for public/get-valuations
- **2023-06-28**
- `private/get-deposit-history` added
- `private/get-withdrawal-history` added
- **2022-11-30**
- Support using `client_oid` to query in `private/get-order-detail` REST API
- **2022-11-10**
- `USD_Stable_Coin` (aka USD Bundle), will be renamed as `USD`. Customer can test the change in UAT from 2022-11-10 before the change is effective in PROD. Target date for PROD is TBD.
- Customer can input both `USD` and `USD_Stable_Coin` to mean the same USD Bundle.
- However, on response, `USD` will be used to mean USD Bundle, instead of `USD_Stable_Coin`.
- **2022-10-31**
- Added `private/create-order-list`, `private/create-subaccount-transfer` REST APIs
- Added `user.account_risk` and `user.position_balance` WebSocket subscriptions
- Added more `period` in `public/get-candlestick` `candlestick.{time_frame}.{instrument_name}` WebSocket subscription
- **2022-09-21** - Added **Unified Wallet and System Label** section, to illustrate the transition from multiple wallets into unified wallet.
- **2022-09-21** - Added new sub-account management endpoints: `private/get-accounts`, `private/create-subaccount-transfer`
- **2022-09-21** - Added new exchange wallet management endpoints: `private/create-withdrawal`, `private/get-deposit-address`, `private/get-curency-networks`
- **2022-09-21** - First publish, based on Derivative Exchange API v1.
---
## Common API Reference
## Common API References
### Naming Conventions
- All **methods and URLs** in **dash-case**
- All **parameters** in **snake_case**
- **Enums** in full **UPPERCASE** and **snake_case**
### Generating the API Key
Before sending any requests, generate a new API key on the Exchange website under **User Center** → **API**. Note down:
- **API Key**
- **Secret Key**
Default settings are "Can Read" only; you can add or remove permissions via the Web UI. You may optionally specify a whitelist of IP addresses; if set, the API can only be used from those IPs.
### REST API Root Endpoints
REST API requests must be sent with **Content-Type: application/json**.
| Environment | REST API |
|-------------|----------|
| **UAT Sandbox** | `https://uat-api.3ona.co/exchange/v1/{method}` |
| **Production** | `https://api.crypto.com/exchange/v1/{method}` |
### Websocket Root Endpoints
| Environment | Websocket (User API) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/user` |
| **Production** | `wss://stream.crypto.com/exchange/v1/user` |
| Environment | Websocket (Market Data) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/market` |
| **Production** | `wss://stream.crypto.com/exchange/v1/market` |
### Rate Limits
#### REST API
For authenticated calls, rate limits are per API method, per API key:
| Method | Limit |
|--------|-------|
| `private/create-order`, `private/cancel-order`, `private/cancel-all-orders` | 15 requests per 100ms each |
| `private/get-order-detail` | 30 requests per 100ms |
| `private/get-trades` | 1 request per second |
| `private/get-order-history` | 1 request per second |
| All others | 3 requests per 100ms each |
For public market data calls, rate limits are per API method, per IP address:
| Method | Limit |
|--------|-------|
| All | 100 requests per second each |
#### Staking
| Method | Limit |
|--------|-------|
| All | 50 requests per second each |
#### Websocket
| Method | Limit |
|--------|-------|
| User API | 150 requests per second |
| Market Data | 100 requests per second |
### Request Format
The following information applies to both REST API and websockets commands:
| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | long | Y | Request identifier (0 to 9,223,372,036,854,775,807). Response echoes the same id. |
| method | string | Y | The method to be invoked (e.g. `private/get-order-detail`). |
| params | object | Y | Parameters for the method. Use `{}` when a method has no parameters. |
| api_key | string | Depends | API key. Required for **private** methods (see Digital Signature). |
| sig | string | Depends | Digital signature. Required for **private** methods. |
| nonce | long | Y | Current timestamp in **milliseconds** since the Unix epoch. |
**⚠️ All numbers must be strings, and must be wrapped in double quotes. e.g. "12.34", instead of 12.34.**
### Digital Signature
For REST API, only 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 pass in the digital signature and API key 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 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.
Besides, for JavaScript client calling `private/get-order-detail` API, it is highly recommended to use STRING format of `order_id` in the JSON request payload, in order to guarantee the correctness of Digital Signature.
#### JavaScript Example
```javascript
const crypto = require("crypto-js");
const signRequest = (request_body, api_key, secret) => {
const { id, method, params, nonce } = request_body;
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)); }, "");
}
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);
const sigPayload = method + id + api_key + paramsString + nonce;
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",
method: "private/get-order-detail",
api_key: apiKey,
params: {
order_id: "53287421324"
},
nonce: "1587846358253",
};
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
```
#### Python Example
```python
API_KEY = "API_KEY"
SECRET_KEY = "SECRET_KEY"
req = {
"id": "14",
"method": "private/create-order-list",
"api_key": API_KEY,
"params": {
"contingency_type": "LIST",
"order_list": [
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "LIMIT",
"price": "0.24",
"quantity": "1.0"
},
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "STOP_LIMIT",
"price": "0.27",
"quantity": "1.0",
"trigger_price": "0.26"
}
]
},
"nonce": str(int(time.time() * 1000))
}
# First ensure the params are alphabetically sorted by key
param_str = ""
MAX_LEVEL = 3
def params_to_str(obj, level):
if level >= MAX_LEVEL:
return str(obj)
return_str = ""
for key in sorted(obj):
return_str += key
if obj[key] is None:
return_str += 'null'
elif isinstance(obj[key], list):
for subObj in obj[key]:
return_str += params_to_str(subObj, level + 1)
else:
return_str += str(obj[key])
return return_str
if "params" in req:
param_str = params_to_str(req['params'], 0)
payload_str = req['method'] + str(req['id']) + req['api_key'] + param_str + str(req['nonce'])
req['sig'] = hmac.new(
bytes(str(SECRET_KEY), 'utf-8'),
msg=bytes(payload_str, 'utf-8'),
digestmod=hashlib.sha256
).hexdigest()
```
#### C# Example
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
private const string API_KEY = "YOUR_API_KEY";
private const string API_SECRET = "YOUR_API_SECRET";
private static string GetSign(Dictionary request)
{
var paramsDict = request["params"] as Dictionary;
// Ensure the params are alphabetically sorted by key
// Note: For nested objects or lists, implement recursive sorting similar to JS/Python examples
string paramString = paramsDict != null
? string.Join("", paramsDict.Keys.OrderBy(key => key).Select(key => key + paramsDict[key]))
: "";
string sigPayload = request["method"].ToString()
+ request["id"].ToString()
+ API_KEY
+ paramString
+ request["nonce"].ToString();
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(API_SECRET)))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(sigPayload));
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
```
#### Java Example
```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiRequestJson {
private Long id;
private String method;
private Map params;
private String sig;
@JsonProperty("api_key")
private String apiKey;
private Long nonce;
}
//------------
public class SigningUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final int MAX_LEVEL = 3;
public static boolean verifySignature(ApiRequestJson apiRequestJson, String secret) {
try {
return genSignature(apiRequestJson, secret).equalsIgnoreCase(apiRequestJson.getSig());
} catch (Exception e) {
return false;
}
}
@SuppressWarnings("unchecked")
public static String getParamString(final Object paramObject) {
StringBuilder sb = new StringBuilder();
appendParamString(sb, paramObject, 0);
return sb.toString();
}
@SuppressWarnings("unchecked")
private static void appendParamString(final StringBuilder paramsStringBuilder, final Object paramObject, final int level) {
if (level >= MAX_LEVEL) {
paramsStringBuilder.append(paramObject.toString());
return;
}
if (paramObject instanceof Map) {
TreeMap params = new TreeMap<>((Map) paramObject);
for (Map.Entry entry : params.entrySet()) {
if (entry.getValue() instanceof Double) {
paramsStringBuilder
.append(entry.getKey())
.append((new BigDecimal(entry.getValue().toString()))
.stripTrailingZeros()
.toPlainString());
} else if (entry.getValue() instanceof List || entry.getValue() instanceof Map) {
paramsStringBuilder
.append(entry.getKey());
appendParamString(paramsStringBuilder, entry.getValue(), level + 1);
} else {
paramsStringBuilder
.append(entry.getKey())
.append(entry.getValue());
}
}
} else if (paramObject instanceof List) {
List list = (List) paramObject;
for (Object o : list) {
appendParamString(paramsStringBuilder, o, level + 1);
}
} else {
paramsStringBuilder.append(paramObject.toString());
}
}
public static String genSignature(ApiRequestJson apiRequestJson, String secret)
throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] byteKey = secret.getBytes(StandardCharsets.UTF_8);
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA256);
mac.init(keySpec);
String paramsString = "";
if (apiRequestJson.getParams() != null) {
paramsString += getParamString(apiRequestJson.getParams());
}
String sigPayload =
apiRequestJson.getMethod()
+ apiRequestJson.getId()
+ apiRequestJson.getApiKey()
+ paramsString
+ (apiRequestJson.getNonce() == null ? "" : apiRequestJson.getNonce());
byte[] macData = mac.doFinal(sigPayload.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(macData);
}
public static ApiRequestJson sign(ApiRequestJson apiRequestJson, String secret)
throws InvalidKeyException, NoSuchAlgorithmException {
apiRequestJson.setSig(genSignature(apiRequestJson, secret));
return apiRequestJson;
}
public static void main(String[] argv) throws InvalidKeyException, NoSuchAlgorithmException {
ApiRequestJson apiRequestJson = ApiRequestJson.builder()
.id(11L)
.apiKey("token")
.method("public/auth")
.nonce(1589594102779L)
.build();
System.out.println(genSignature(apiRequestJson, "secretKey"));
System.out.println(sign(apiRequestJson, "secretKey"));
}
}
```
### Response Format
| Name | Type | Description |
|------|------|-------------|
| id | long | Original request identifier (or -1 if omitted in request). |
| method | string | Method invoked. |
| result | object | Result object (present on success). |
| code | int | 0 for success; see Response and Reason Codes |
| message | string | Optional; server or error message. |
| original | string | Optional; original request as escaped string (for error cases). |
### Response and Reason Codes
#### 200 OK
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 200 | 0 | --:Success |
| 200 | 40401 | NOT_FOUND:Not found |
| 200 | 43012 | SELF_TRADE_PREVENTION:Canceled due to Self Trade Prevention |
#### 400 Bad Request
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 400 | 202 | ACCOUNT_IS_SUSPENDED:Account is suspended |
| 400 | 204 | DUPLICATE_CLORDID:Duplicate client order id |
| 400 | 207 | NO_MARK_PRICE:No mark price |
| 400 | 208 | INSTRUMENT_NOT_TRADABLE:Instrument is not tradable |
| 400 | 209 | INVALID_INSTRUMENT:Instrument is invalid |
| 400 | 213 | INVALID_ORDERQTY:Invalid order quantity |
| 400 | 218 | INVALID_ORDTYPE:Invalid order_type |
| 400 | 220 | INVALID_SIDE:Invalid side |
| 400 | 221 | INVALID_TIF:Invalid time_in_force |
| 400 | 222 | STALE_MARK_PRICE:Stale mark price |
| 400 | 223 | NO_CLORDID:No client order id |
| 400 | 224 | REJ_BY_MATCHING_ENGINE:Rejected by matching engine |
| 400 | 225 | EXCEED_MAXIMUM_ENTRY_LEVERAGE:Exceeds maximum entry leverage |
| 400 | 226 | INVALID_LEVERAGE:Invalid leverage |
| 400 | 227 | INVALID_SLIPPAGE:Invalid slippage |
| 400 | 228 | INVALID_FLOOR_PRICE:Invalid floor price |
| 400 | 229 | INVALID_REF_PRICE:Invalid ref price |
| 400 | 230 | INVALID_REF_PRICE_TYPE:Invalid ref price type |
| 400 | 308 | INVALID_PRICE:Invalid price |
| 400 | 314 | EXCEEDS_MAX_ORDER_SIZE:Exceeds max order size |
| 400 | 315 | FAR_AWAY_LIMIT_PRICE:Far away limit price |
| 400 | 318 | EXCEEDS_MAX_ALLOWED_ORDERS:Exceeds max allowed orders |
| 400 | 319 | EXCEEDS_MAX_POSITION_SIZE:Exceeds max position size |
| 400 | 401 | ACCOUNT_DOES_NOT_EXIST:Account does not exist |
| 400 | 408 | MARGIN_UNIT_IS_SUSPENDED:Margin unit is suspended |
| 400 | 30024 | MAX_AMOUNT_VIOLATED:If create-withdrawal call quantity > max_withdrawal_balance in user-balance api |
| 400 | 40001 | BAD_REQUEST:Bad request |
| 400 | 40002 | METHOD_NOT_FOUND:Method not found |
| 400 | 40003 | INVALID_REQUEST:Invalid request |
| 400 | 40004 | MISSING_OR_INVALID_ARGUMENT:Required argument is blank or missing |
| 400 | 40005 | INVALID_DATE:Invalid date |
| 400 | 40006 | DUPLICATE_REQUEST:Duplicate request received |
| 400 | 40102 | INVALID_NONCE:Nonce value differs by more than 60 seconds |
| 400 | 40107 | EXCEED_MAX_SUBSCRIPTIONS:Session subscription limit has been exceeded |
| 400 | 50001 | ERR_INTERNAL:Internal error |
| 400 | 50002 | DW_CREDIT_LINE_NOT_MAINTAINED:If create-withdrawal call breaches credit line check |
#### 401 Unauthorized
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 401 | 40101 | UNAUTHORIZED:Not authenticated, or key/signature incorrect |
| 401 | 40103 | IP_ILLEGAL:IP address not whitelisted |
| 401 | 40104 | USER_TIER_INVALID:Disallowed based on user tier |
#### 408 Request Timeout
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 408 | 40801 | REQUEST_TIMEOUT:Request has timed out |
#### 429 Too Many Requests
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 429 | 42901 | TOO_MANY_REQUESTS:Requests have exceeded rate limits |
#### 500 Internal Server Error
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 500 | 201 | NO_POSITION:No position |
| 500 | 203 | ACCOUNTS_DO_NOT_MATCH:Accounts do not match |
| 500 | 205 | DUPLICATE_ORDERID:Duplicate order id |
| 500 | 206 | INSTRUMENT_EXPIRED:Instrument has expired |
| 500 | 210 | INVALID_ACCOUNT:Account is invalid |
| 500 | 211 | INVALID_CURRENCY:Currency is invalid |
| 500 | 212 | INVALID_ORDERID:Invalid order id |
| 500 | 214 | INVALID_SETTLE_CURRENCY:Invalid settlement currency |
| 500 | 215 | INVALID_FEE_CURRENCY:Invalid fee currency |
| 500 | 216 | INVALID_POSITION_QTY:Invalid position quantity |
| 500 | 217 | INVALID_OPEN_QTY:Invalid open quantity |
| 500 | 219 | INVALID_EXECINST:Invalid exec_inst |
| 500 | 301 | ACCOUNT_IS_IN_MARGIN_CALL:Account is in margin call |
| 500 | 302 | EXCEEDS_ACCOUNT_RISK_LIMIT:Exceeds account risk limit |
| 500 | 303 | EXCEEDS_POSITION_RISK_LIMIT:Exceeds position risk limit |
| 500 | 304 | ORDER_WILL_LEAD_TO_IMMEDIATE_LIQUIDATION:Order will lead to immediate liquidation |
| 500 | 305 | ORDER_WILL_TRIGGER_MARGIN_CALL:Order will trigger margin call |
| 500 | 306 | INSUFFICIENT_AVAILABLE_BALANCE:Insufficient available balance |
| 500 | 307 | INVALID_ORDSTATUS:Invalid order status |
| 500 | 309 | MARKET_IS_NOT_OPEN:Market is not open |
| 500 | 310 | ORDER_PRICE_BEYOND_LIQUIDATION_PRICE:Order price beyond liquidation price |
| 500 | 311 | POSITION_IS_IN_LIQUIDATION:Position is in liquidation |
| 500 | 312 | ORDER_PRICE_GREATER_THAN_LIMITUPPRICE:Order price is greater than the limit up price |
| 500 | 313 | ORDER_PRICE_LESS_THAN_LIMITDOWNPRICE:Order price is less than the limit down price |
| 500 | 316 | NO_ACTIVE_ORDER:No active order |
| 500 | 317 | POSITION_NO_EXIST:Position does not exist |
| 500 | 320 | EXCEEDS_INITIAL_MARGIN:Exceeds initial margin |
| 500 | 321 | EXCEEDS_MAX_AVAILABLE_BALANCE:Exceeds maximum available balance |
| 500 | 406 | ACCOUNT_IS_NOT_ACTIVE:Account is not active |
| 500 | 407 | MARGIN_UNIT_DOES_NOT_EXIST:Margin unit does not exist |
| 500 | 409 | INVALID_USER:Invalid user |
| 500 | 410 | USER_IS_NOT_ACTIVE:User is not active |
| 500 | 411 | USER_NO_DERIV_ACCESS:User does not have derivative access |
| 500 | 412 | ACCOUNT_NO_DERIV_ACCESS:Account does not have derivative access |
| 500 | 415 | BELOW_MIN_ORDER_SIZE:Below Min. Order Size |
| 500 | 501 | EXCEED_MAXIMUM_EFFECTIVE_LEVERAGE:Exceeds maximum effective leverage |
| 500 | 604 | INVALID_COLLATERAL_PRICE:Invalid collateral price |
| 500 | 605 | INVALID_MARGIN_CALC:Invalid margin calculation |
| 500 | 606 | EXCEED_ALLOWED_SLIPPAGE:Exceed allowed slippage |
| 500 | 613 | INVALID_ISOLATION_ID:Invalid isolation ID |
| 500 | 614 | EXCEEDS_ISOLATED_POSITION_LIMIT:Exceeds maximum allowed number of isolated position |
| 500 | 615 | ACCOUNT_DOES_NOT_SUPPORT_ISOLATED_POSITION:Account does not support isolated position |
| 500 | 616 | CREATE_ISOLATED_POSITION_FAILED:Failed to create isolated position |
| 500 | 617 | DUPLICATED_INSTRUMENT_ORDER_FOR_ISOLATED_MARGIN:Account already have isolated position with same instrument |
| 500 | 618 | TOO_MANY_PENDING_ISOLATED_MARGIN_REQUESTS:Exceeds request limit for isolated margin order |
| 500 | 619 | UNSUPPORTED_OPERATION_ON_ISOLATED_POSITION:Unsupported operation on isolated position |
| 500 | 620 | CREATE_ISOLATED_POSITION_TIMEOUT:Request for create isolated position has timed out |
| 400 | 1110 | REDUCE_ONLY_REJECTED:Rejected REDUCE_ONLY create-order request |
| 500 | 43003 | FILL_OR_KILL:FOK order has not been filled and cancelled |
| 500 | 43004 | IMMEDIATE_OR_CANCEL:IOC order has not been filled and cancelled |
| 500 | 43005 | POST_ONLY_REJ:Rejected POST_ONLY create-order request (normally happened when exec_inst contains POST_ONLY but time_in_force is NOT GOOD_TILL_CANCEL) |
| 500 | 120009 | REJECTED:Request rejected by upstream service |
| 500 | 130008 | NON_APPLICABLE:Operation not applicable for current state |
### 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 |
### 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.
### Common Issues
#### TOO_MANY_REQUESTS After Websocket Connects
Websocket rate limits are pro-rated based on the calendar-second that the websocket connection was opened.
This means, depending on the fraction of the calendar-second that the connection was established, the rate limit could be pro-rated to a small number.
By adding a 1-second sleep after establishing the websocket connection, and before requests are sent, this will ensure the rate limit is properly reset and sync'd to your session.
This will avoid occurrences of rate-limit (TOO_MANY_REQUESTS) errors.
#### INVALID_NONCE On All Requests
The nonce should be the UTC Unix timestamp in milliseconds.
If this has been carefully checked, then the issue occurs when the system clock of the client machine is greater than 60 seconds in the future / past.
Usually, re-syncing with the NTP time server on the client machine will correct the issue.
If the issue persists, you can try deliberately subtracting N seconds from the nonce to force it to be N seconds in the past, which is still within the 60-second past tolerance.
---
## REST API
## Welcome
Welcome to the Crypto.com Exchange API v1 reference documentation.
The Crypto.com Exchange API v1 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.
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, as well as sample requests and code snippets in JavaScript, Python which can be viewed on the right.
### Notes on Exchange Upgrade and API Versions
- Exchange v1 API is the latest version of API which can trade Spot / Derivatives / Margin.
- Derivatives v1 API has been upgraded into Exchange v1 API with additional capabilities for Spot Trading / Margin Trading / Wallet Management. As Exchange v1 API is a superset of Derivatives v1 API, existing customer can continue using the same for trading.
- For full details about the exchange upgrade, please refer to this (blog post)[https://crypto.com/product-news/introducing-the-gen-3-0-crypto-com-exchange] with FAQ documents.
---
## Advanced Order Management(Websocket)
Advanced Order Management provides trigger orders and multi-leg execution strategies beyond basic LIMIT and MARKET orders. Use these endpoints for conditional order execution based on price triggers.
## Trigger Orders
Trigger orders activate when a reference price condition is met. Use [`private/advanced/create-order`](/docs/api/rest/private-advanced-create-order) to create trigger orders.
| Type | Description |
|------|-------------|
| `STOP_LOSS` | Converts to a market order when trigger price is reached. Used to limit losses. |
| `STOP_LIMIT` | Converts to a limit order when trigger price is reached. Offers price control on stop execution. |
| `TAKE_PROFIT` | Market order activated when price moves favorably to the trigger level. Used to lock in gains. |
| `TAKE_PROFIT_LIMIT` | Limit order activated when price moves favorably to the trigger level. |
Trigger orders require:
- `ref_price` — the trigger price
- `ref_price_type` — reference price source: `MARK_PRICE` (default), `INDEX_PRICE`, or `LAST_PRICE`
## Multi-Leg Strategies
Multi-leg orders link multiple orders together with conditional execution logic.
| Strategy | Description | Endpoint |
|----------|-------------|----------|
| **OCO** (One-Cancels-Other) | Two orders where filling one cancels the other. Typically pairs a take-profit with a stop-loss. | [`private/advanced/create-oco`](/docs/api/rest/private-advanced-create-oco) |
| **OTO** (One-Triggers-Other) | Primary order triggers a secondary order when filled. Used to attach TP/SL to an entry order. | [`private/advanced/create-oto`](/docs/api/rest/private-advanced-create-oto) |
| **OTOCO** (One-Triggers-OCO) | Primary order triggers an OCO pair when filled. Entry order with both TP and SL attached. | [`private/advanced/create-otoco`](/docs/api/rest/private-advanced-create-otoco) |
## Contingency Types
Multi-leg orders use contingency types to define the relationship between legs:
| Type | Description |
|------|-------------|
| `OCO` | One-Cancels-Other: two orders, one cancels when the other fills |
| `SPOT_ATTACH` | Attach trigger orders to a spot position |
| `DERIV_ATTACH` | Attach trigger orders to a derivatives position (supports isolated margin) |
## Order Management
- [`private/advanced/amend-order`](/docs/api/rest/private-advanced-amend-order) — modify trigger price or quantity
- [`private/advanced/cancel-order`](/docs/api/rest/private-advanced-cancel-order) — cancel a single advanced order
- [`private/advanced/cancel-all-orders`](/docs/api/rest/private-advanced-cancel-all-orders) — cancel all advanced orders for an instrument
- [`private/advanced/get-open-orders`](/docs/api/rest/private-advanced-get-open-orders) — retrieve open advanced orders
- [`private/advanced/get-order-history`](/docs/api/rest/private-advanced-get-order-history) — retrieve advanced order history
## Real-Time Updates
Subscribe to `user.advanced.order` for real-time advanced order lifecycle events.
---
## Crypto.com Exchange WebSocket API
Version: 1.0.0
Crypto.com Exchange WebSocket API
## Welcome
Welcome to the Crypto.com Exchange API v1 reference documentation.
The Crypto.com Exchange API v1 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.
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, as well as sample requests and code snippets in JavaScript, Python which can be viewed on the right.
### Notes on Exchange Upgrade and API Versions
- Exchange v1 API is the latest version of API which can trade Spot / Derivatives / Margin.
- Derivatives v1 API has been upgraded into Exchange v1 API with additional capabilities for Spot Trading / Margin Trading / Wallet Management. As Exchange v1 API is a superset of Derivatives v1 API, existing customer can continue using the same for trading.
- For full details about the exchange upgrade, please refer to this (blog post)[https://crypto.com/product-news/introducing-the-gen-3-0-crypto-com-exchange] with FAQ documents.
## Breaking Change Schedule
- On 2025-12-17 8:00 UTC,
The current trigger order creation/cancellation will be migrated to Advanced Order Management API.
- On 2025-02-27 8:00 UTC,
For `book.{instrument_name}.{depth}`, the full snapshot subscription (`book_subscription_type=SNAPSHOT`) `100ms` frequency is removed.
Customers wishing to continue with the faster `100ms` frequency should switch to the delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`).
This higher performing subscription benefits the user with reduced bandwidth/processing compared to the snapshot subscription.
For a transition period, users subscribing to the removed `100ms` snapshot will receive the `500ms` subscription.
The `book.{instrument_name}` subscription (default depth) will be removed.
Customers should use the explicit `book.{instrument_name}.{depth}` subscription and specify the required depth.
For a transition period, users subscribing to the removed subscription will receive the default `50` depth subscription.
- These changes will take place around 17 December 2023 8:00 UTC.
- Market Data wildcard ticker subscription will be removed. Users should use the instrument specific subscription.
## Change Log
- **2026-05-21**
- `public/get-instruments` response updated, new field `product_type` was added
- Trading Bot API section was added:
`private/bot/create-trading-bot` (DCA, TWAP, GRID, FUNDING_ARBITRAGE)
`private/bot/terminate-trading-bot`
`private/bot/update-trading-bot`
`private/bot/pause-trading-bot`
`private/bot/resume-trading-bot`
`private/bot/get-trading-bots`
`private/bot/get-trading-bot-executions`
- **2026-05-07**
- Advanced Order Management API section was updated for DerivAttach
- `private/advanced/create-oto` and `private/advanced/create-otoco` — contingency type is now resolved from instrument type: spot instruments create SPOT_ATTACH, derivative instruments create DERIV_ATTACH. DerivAttach supports `isolation_id`, `leverage`, `isolated_margin_amount` on the primary leg and `ISOLATED_MARGIN` in `exec_inst`. Trigger legs inherit isolation mode from the parent.
- `private/advanced/create-order` — `attach_order_id` now applies to both SpotAttach and DerivAttach. New optional field `attach_isolation_id` for DerivAttach attach-to-position (derivatives only).
- `private/advanced/cancel-oto` and `private/advanced/cancel-otoco` — updated to cover both SPOT_ATTACH and DERIV_ATTACH.
- `private/advanced/cancel-all-orders` — new optional field `position_type` (CROSS_MARGIN, ISOLATED_MARGIN).
- `private/advanced/get-open-orders`, `private/advanced/get-order-detail`, `private/advanced/get-order-history`, and `user.advance.order` — response attributes extended with `exchange_order_id`, `ref_price`, `ref_price_type`, `reject_reason`, `attach_isolation_id`, `isolation_id`, `isolation_type`, `leverage`, `isolated_margin_amount`. `contingency_type` now includes DERIV_ATTACH.
- `private/advanced/amend-order` — corrected required/optional flags: `new_price` is Y, `new_quantity` is Y, `new_ref_price` is N.
- **2026-04-29**
- Fee Credits
- `private/get-fee-credit-balances` was added
- `private/get-trades` response updated, new field `fee_credits` was added
- `user.trade.{instrument_name}` response updated, new field `fee_credits` was added
- **2026-04-07**
- `private/get-accounts` response updated, new field `hierarchy` was added
- **2026-04-01**
- `private/create-order` request updated, `REDUCE_ONLY` was added to `exec_inst`
- **2026-01-08**
- Add support for isolated position
- `private/create-isolated-margin-transfer` was added
- `private/change-isolated-margin-leverage` was added
- `private/user-balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/user-balance-history` response updated, new field `i` was added
- `private/get-subaccount-balances` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/get-positions` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/create-order` request updated, new optional fields `isolation_id`, `leverage`, `isolated_margin_amount` were added, `exec_inst` added support for `ISOALTED_MARGIN`
- `private/close-position` request updated, new optional field `isolation_id` was added
- `private/get-open-orders` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-detail` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-history` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-trades` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-transactions` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `user.order.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.trade.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `user.positions` response updated, new fields `isolation_id`, `leverage`, `isolation_type`, `liquidation_price` and `isolated_margin_balance` were added
- `user.account_risk` response updated, new fields `total_isolated_cash_balance`, `isolated_positions` were added
- `user.position_balance` response updated, new field `isolated_positions` was added
- **2025-03-26**
- `transaction_time` was added into `user.order.{instrument_name}`
- **2025-11-18**
- `public/get-risk-parameters` was added new columns
- **2025-10-16**
- `Advanced Order Management API` section was updated
- **2025-07-17**
- `private/fiat/fiat-deposit-info` was added
- `private/fiat/fiat-deposit-history` was added
- `private/fiat/fiat-withdraw-history` was added
- `private/fiat/fiat-create-withdraw` was added
- `private/fiat/fiat-get-bank-accounts` was added
- `private/fiat/fiat-transaction-quota` was added
- `private/fiat/fiat-transaction-limit` was added
- **2025-07-04**
- `private/create-order` exec_inst was added `SMART_POST_ONLY`
- `private/create-order-list (LIST)` exec_inst was added `SMART_POST_ONLY`
- `private/get-open-orders` exec_inst was added `SMART_POST_ONLY`
- `private/get-order-detail` was added, exec_inst was added `SMART_POST_ONLY`
- `private/get-order-history` exec_inst was added `SMART_POST_ONLY`
- **2025-06-10**
- `private/amend-order` was added
- `public/get-announcements` was added
- **2025-05-29**
- transaction_time_ns field was added into `user.order.{instrument_name}` response
- **2025-03-14**
- Removed deprecated attributes system_label in `private/get-accounts`
- **2025-03-06**
- Removed deprecated `book.{instrument_name}` default book subscription
- Removed deprecated 100ms interval from full snapshot `book.{instrument_name}.{depth}` book subscription
- **2025-03-04**
- Remove section: `Unified Wallet and System Label`
- **2025-01-27**
- `book.{instrument_name}.{depth}` - The following additional update frequencies are now supported:
Full snapshot subscription (`book_subscription_type=SNAPSHOT`) `500ms`
Delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`) `100ms`
- **2024-12-11**
- `private/create-order` fee_instrument_name was added
- **2024-10-02**
- `public/get-risk-parameters` was added
- **2024-08-15**
- `private/get-fee-rate` was added
- `private/get-instrument-fee-rate` was added
- **2024-07-12**
- Staking API added:
`private/staking/stake`
`private/staking/unstake`
`private/staking/get-staking-position`
`private/staking/get-staking-instruments`
`private/staking/get-open-stake`
`private/staking/get-stake-history`
`private/staking/get-reward-history`
`private/staking/convert`
`private/staking/get-open-convert`
`private/staking/get-convert-history`
`public/staking/get-conversion-rate`
- **2024-06-27**
- `private/create-order` self-trade prevent (STP) was added
- `private/create-order-list (LIST)` self-trade prevent (STP) was added
- **2024-02-12**
- `public/get-trades`, `trade.{instrument_name}` subscription, clarification for the public trade side field
- Side is the side of the taker order
- `book.{instrument_name}.{depth}` clarifications for book delta sequence number handling and re-subscription
- **2024-01-04**
- Market data websocket subscription enhancements:
- `book.{instrument_name}` - The `subscription` result value is now explicit
e.g. previous `"subscription": "book.BTC_USD"` -\> new `"subscription": "book.BTC_USD.50"`
- `book.{instrument_name}.{depth}` - For delta updates, the fixed 500ms delta full book snapshot heartbeat is replaced with empty delta in the case of no book changes
- `ticker` - Documented existing 'bs' and 'ks' fields (bid/ask size)
- `settlement` - For wildcard subscription, the `subscription` result value is now explicit
e.g. previous `"subscription": "settlement"` -\> new `"subscription": "settlement.BTCUSD-231124"`
- Applied consistent field ordering for all market data subscriptions (`book`, `ticker`, `trade`, `candlestick`, `index`, `mark`, `settlement`, `funding`, `estimatedfunding`).
Result fields are always in the following order:
`id, method, code, instrument_name, subscription, channel`
- Market data REST `public/get-trades`
- Added additional `tn` nanoseconds timestamp field to the trade response
- Clarified timestamp pagination parameters
- **2023-12-18**
- Market Data wildcard ticker subscription removed. Users should use the instrument specific subscription.
- **2023-12-11**
- Introduced Market Data subscription limiting. Refer to Market Data Websocket Subscription Limits for more details
- **2023-10-31**
- `user.balance`, `private/user-balance` will be updated:
1. Existing field total_margin_balance will represent new margin balance calculation without haircut.
2. Existing field total_initial_margin previously is made up of position IM only. On effective date, this field will represent the total sum of total_position_im + total_haircut
3. New field total_position_im will be introduced to represent initial margin requirement to support open positions and orders
4. New field total_haircut will be introduced to represent the total haircut on eligible collateral token assets. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- `user.balance`, `user.account_risk`, `private/user-balance`, `private/get-subaccount-balances` will be updated:
1. New field collateral_eligible will be introduced to indicate if token is eligible Collateral
2. collateral_weight will be deprecated
3. New field haircut will be introduced to show haircut of eligible collateral token instead of collateral Weight. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- **2023-08-11**
- `private/create-order-list (LIST)` for batch order creation added
- `private/cancel-order-list (LIST)` for batch order cancel added
- **2023-07-31**
- Market Data Websocket Subscriptions is effective:
- `funding.{instrument_name}` - channel will return the fixed hourly rate that will settle at the end of the hour.
- `estimatedfunding.{instrument_name}` - channel will return the estimated hourly rate that will begin in the next interval.
- Added new "funding_rate" and "estimated_funding_rate" valuation types for public/get-valuations
- **2023-06-28**
- `private/get-deposit-history` added
- `private/get-withdrawal-history` added
- **2022-11-30**
- Support using `client_oid` to query in `private/get-order-detail` REST API
- **2022-11-10**
- `USD_Stable_Coin` (aka USD Bundle), will be renamed as `USD`. Customer can test the change in UAT from 2022-11-10 before the change is effective in PROD. Target date for PROD is TBD.
- Customer can input both `USD` and `USD_Stable_Coin` to mean the same USD Bundle.
- However, on response, `USD` will be used to mean USD Bundle, instead of `USD_Stable_Coin`.
- **2022-10-31**
- Added `private/create-order-list`, `private/create-subaccount-transfer` REST APIs
- Added `user.account_risk` and `user.position_balance` WebSocket subscriptions
- Added more `period` in `public/get-candlestick` `candlestick.{time_frame}.{instrument_name}` WebSocket subscription
- **2022-09-21** - Added **Unified Wallet and System Label** section, to illustrate the transition from multiple wallets into unified wallet.
- **2022-09-21** - Added new sub-account management endpoints: `private/get-accounts`, `private/create-subaccount-transfer`
- **2022-09-21** - Added new exchange wallet management endpoints: `private/create-withdrawal`, `private/get-deposit-address`, `private/get-curency-networks`
- **2022-09-21** - First publish, based on Derivative Exchange API v1.
## Common API References
### Naming Conventions
- All **methods and URLs** in **dash-case**
- All **parameters** in **snake_case**
- **Enums** in full **UPPERCASE** and **snake_case**
### Generating the API Key
Before sending any requests, generate a new API key on the Exchange website under **User Center** → **API**. Note down:
- **API Key**
- **Secret Key**
Default settings are "Can Read" only; you can add or remove permissions via the Web UI. You may optionally specify a whitelist of IP addresses; if set, the API can only be used from those IPs.
### REST API Root Endpoints
REST API requests must be sent with **Content-Type: application/json**.
| Environment | REST API |
|-------------|----------|
| **UAT Sandbox** | `https://uat-api.3ona.co/exchange/v1/{method}` |
| **Production** | `https://api.crypto.com/exchange/v1/{method}` |
### Websocket Root Endpoints
| Environment | Websocket (User API) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/user` |
| **Production** | `wss://stream.crypto.com/exchange/v1/user` |
| Environment | Websocket (Market Data) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/market` |
| **Production** | `wss://stream.crypto.com/exchange/v1/market` |
### Rate Limits
#### REST API
For authenticated calls, rate limits are per API method, per API key:
| Method | Limit |
|--------|-------|
| `private/create-order`, `private/cancel-order`, `private/cancel-all-orders` | 15 requests per 100ms each |
| `private/get-order-detail` | 30 requests per 100ms |
| `private/get-trades` | 1 request per second |
| `private/get-order-history` | 1 request per second |
| All others | 3 requests per 100ms each |
For public market data calls, rate limits are per API method, per IP address:
| Method | Limit |
|--------|-------|
| All | 100 requests per second each |
#### Staking
| Method | Limit |
|--------|-------|
| All | 50 requests per second each |
#### Websocket
| Method | Limit |
|--------|-------|
| User API | 150 requests per second |
| Market Data | 100 requests per second |
### Request Format
The following information applies to both REST API and websockets commands:
| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | long | Y | Request identifier (0 to 9,223,372,036,854,775,807). Response echoes the same id. |
| method | string | Y | The method to be invoked (e.g. `private/get-order-detail`). |
| params | object | Y | Parameters for the method. Use `{}` when a method has no parameters. |
| api_key | string | Depends | API key. Required for **private** methods (see Digital Signature). |
| sig | string | Depends | Digital signature. Required for **private** methods. |
| nonce | long | Y | Current timestamp in **milliseconds** since the Unix epoch. |
**⚠️ All numbers must be strings, and must be wrapped in double quotes. e.g. "12.34", instead of 12.34.**
### Digital Signature
For REST API, only 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 pass in the digital signature and API key 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 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.
Besides, for JavaScript client calling `private/get-order-detail` API, it is highly recommended to use STRING format of `order_id` in the JSON request payload, in order to guarantee the correctness of Digital Signature.
#### JavaScript Example
```javascript
const crypto = require("crypto-js");
const signRequest = (request_body, api_key, secret) => {
const { id, method, params, nonce } = request_body;
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)); }, "");
}
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);
const sigPayload = method + id + api_key + paramsString + nonce;
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",
method: "private/get-order-detail",
api_key: apiKey,
params: {
order_id: "53287421324"
},
nonce: "1587846358253",
};
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
```
#### Python Example
```python
API_KEY = "API_KEY"
SECRET_KEY = "SECRET_KEY"
req = {
"id": "14",
"method": "private/create-order-list",
"api_key": API_KEY,
"params": {
"contingency_type": "LIST",
"order_list": [
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "LIMIT",
"price": "0.24",
"quantity": "1.0"
},
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "STOP_LIMIT",
"price": "0.27",
"quantity": "1.0",
"trigger_price": "0.26"
}
]
},
"nonce": str(int(time.time() * 1000))
}
# First ensure the params are alphabetically sorted by key
param_str = ""
MAX_LEVEL = 3
def params_to_str(obj, level):
if level >= MAX_LEVEL:
return str(obj)
return_str = ""
for key in sorted(obj):
return_str += key
if obj[key] is None:
return_str += 'null'
elif isinstance(obj[key], list):
for subObj in obj[key]:
return_str += params_to_str(subObj, level + 1)
else:
return_str += str(obj[key])
return return_str
if "params" in req:
param_str = params_to_str(req['params'], 0)
payload_str = req['method'] + str(req['id']) + req['api_key'] + param_str + str(req['nonce'])
req['sig'] = hmac.new(
bytes(str(SECRET_KEY), 'utf-8'),
msg=bytes(payload_str, 'utf-8'),
digestmod=hashlib.sha256
).hexdigest()
```
#### C# Example
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
private const string API_KEY = "YOUR_API_KEY";
private const string API_SECRET = "YOUR_API_SECRET";
private static string GetSign(Dictionary request)
{
var paramsDict = request["params"] as Dictionary;
// Ensure the params are alphabetically sorted by key
// Note: For nested objects or lists, implement recursive sorting similar to JS/Python examples
string paramString = paramsDict != null
? string.Join("", paramsDict.Keys.OrderBy(key => key).Select(key => key + paramsDict[key]))
: "";
string sigPayload = request["method"].ToString()
+ request["id"].ToString()
+ API_KEY
+ paramString
+ request["nonce"].ToString();
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(API_SECRET)))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(sigPayload));
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
```
#### Java Example
```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiRequestJson {
private Long id;
private String method;
private Map params;
private String sig;
@JsonProperty("api_key")
private String apiKey;
private Long nonce;
}
//------------
public class SigningUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final int MAX_LEVEL = 3;
public static boolean verifySignature(ApiRequestJson apiRequestJson, String secret) {
try {
return genSignature(apiRequestJson, secret).equalsIgnoreCase(apiRequestJson.getSig());
} catch (Exception e) {
return false;
}
}
@SuppressWarnings("unchecked")
public static String getParamString(final Object paramObject) {
StringBuilder sb = new StringBuilder();
appendParamString(sb, paramObject, 0);
return sb.toString();
}
@SuppressWarnings("unchecked")
private static void appendParamString(final StringBuilder paramsStringBuilder, final Object paramObject, final int level) {
if (level >= MAX_LEVEL) {
paramsStringBuilder.append(paramObject.toString());
return;
}
if (paramObject instanceof Map) {
TreeMap params = new TreeMap<>((Map) paramObject);
for (Map.Entry entry : params.entrySet()) {
if (entry.getValue() instanceof Double) {
paramsStringBuilder
.append(entry.getKey())
.append((new BigDecimal(entry.getValue().toString()))
.stripTrailingZeros()
.toPlainString());
} else if (entry.getValue() instanceof List || entry.getValue() instanceof Map) {
paramsStringBuilder
.append(entry.getKey());
appendParamString(paramsStringBuilder, entry.getValue(), level + 1);
} else {
paramsStringBuilder
.append(entry.getKey())
.append(entry.getValue());
}
}
} else if (paramObject instanceof List) {
List list = (List) paramObject;
for (Object o : list) {
appendParamString(paramsStringBuilder, o, level + 1);
}
} else {
paramsStringBuilder.append(paramObject.toString());
}
}
public static String genSignature(ApiRequestJson apiRequestJson, String secret)
throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] byteKey = secret.getBytes(StandardCharsets.UTF_8);
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA256);
mac.init(keySpec);
String paramsString = "";
if (apiRequestJson.getParams() != null) {
paramsString += getParamString(apiRequestJson.getParams());
}
String sigPayload =
apiRequestJson.getMethod()
+ apiRequestJson.getId()
+ apiRequestJson.getApiKey()
+ paramsString
+ (apiRequestJson.getNonce() == null ? "" : apiRequestJson.getNonce());
byte[] macData = mac.doFinal(sigPayload.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(macData);
}
public static ApiRequestJson sign(ApiRequestJson apiRequestJson, String secret)
throws InvalidKeyException, NoSuchAlgorithmException {
apiRequestJson.setSig(genSignature(apiRequestJson, secret));
return apiRequestJson;
}
public static void main(String[] argv) throws InvalidKeyException, NoSuchAlgorithmException {
ApiRequestJson apiRequestJson = ApiRequestJson.builder()
.id(11L)
.apiKey("token")
.method("public/auth")
.nonce(1589594102779L)
.build();
System.out.println(genSignature(apiRequestJson, "secretKey"));
System.out.println(sign(apiRequestJson, "secretKey"));
}
}
```
### Response Format
| Name | Type | Description |
|------|------|-------------|
| id | long | Original request identifier (or -1 if omitted in request). |
| method | string | Method invoked. |
| result | object | Result object (present on success). |
| code | int | 0 for success; see Response and Reason Codes |
| message | string | Optional; server or error message. |
| original | string | Optional; original request as escaped string (for error cases). |
### Response and Reason Codes
#### 200 OK
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 200 | 0 | --:Success |
| 200 | 40401 | NOT_FOUND:Not found |
| 200 | 43012 | SELF_TRADE_PREVENTION:Canceled due to Self Trade Prevention |
#### 400 Bad Request
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 400 | 202 | ACCOUNT_IS_SUSPENDED:Account is suspended |
| 400 | 204 | DUPLICATE_CLORDID:Duplicate client order id |
| 400 | 207 | NO_MARK_PRICE:No mark price |
| 400 | 208 | INSTRUMENT_NOT_TRADABLE:Instrument is not tradable |
| 400 | 209 | INVALID_INSTRUMENT:Instrument is invalid |
| 400 | 213 | INVALID_ORDERQTY:Invalid order quantity |
| 400 | 218 | INVALID_ORDTYPE:Invalid order_type |
| 400 | 220 | INVALID_SIDE:Invalid side |
| 400 | 221 | INVALID_TIF:Invalid time_in_force |
| 400 | 222 | STALE_MARK_PRICE:Stale mark price |
| 400 | 223 | NO_CLORDID:No client order id |
| 400 | 224 | REJ_BY_MATCHING_ENGINE:Rejected by matching engine |
| 400 | 225 | EXCEED_MAXIMUM_ENTRY_LEVERAGE:Exceeds maximum entry leverage |
| 400 | 226 | INVALID_LEVERAGE:Invalid leverage |
| 400 | 227 | INVALID_SLIPPAGE:Invalid slippage |
| 400 | 228 | INVALID_FLOOR_PRICE:Invalid floor price |
| 400 | 229 | INVALID_REF_PRICE:Invalid ref price |
| 400 | 230 | INVALID_REF_PRICE_TYPE:Invalid ref price type |
| 400 | 308 | INVALID_PRICE:Invalid price |
| 400 | 314 | EXCEEDS_MAX_ORDER_SIZE:Exceeds max order size |
| 400 | 315 | FAR_AWAY_LIMIT_PRICE:Far away limit price |
| 400 | 318 | EXCEEDS_MAX_ALLOWED_ORDERS:Exceeds max allowed orders |
| 400 | 319 | EXCEEDS_MAX_POSITION_SIZE:Exceeds max position size |
| 400 | 401 | ACCOUNT_DOES_NOT_EXIST:Account does not exist |
| 400 | 408 | MARGIN_UNIT_IS_SUSPENDED:Margin unit is suspended |
| 400 | 30024 | MAX_AMOUNT_VIOLATED:If create-withdrawal call quantity > max_withdrawal_balance in user-balance api |
| 400 | 40001 | BAD_REQUEST:Bad request |
| 400 | 40002 | METHOD_NOT_FOUND:Method not found |
| 400 | 40003 | INVALID_REQUEST:Invalid request |
| 400 | 40004 | MISSING_OR_INVALID_ARGUMENT:Required argument is blank or missing |
| 400 | 40005 | INVALID_DATE:Invalid date |
| 400 | 40006 | DUPLICATE_REQUEST:Duplicate request received |
| 400 | 40102 | INVALID_NONCE:Nonce value differs by more than 60 seconds |
| 400 | 40107 | EXCEED_MAX_SUBSCRIPTIONS:Session subscription limit has been exceeded |
| 400 | 50001 | ERR_INTERNAL:Internal error |
| 400 | 50002 | DW_CREDIT_LINE_NOT_MAINTAINED:If create-withdrawal call breaches credit line check |
#### 401 Unauthorized
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 401 | 40101 | UNAUTHORIZED:Not authenticated, or key/signature incorrect |
| 401 | 40103 | IP_ILLEGAL:IP address not whitelisted |
| 401 | 40104 | USER_TIER_INVALID:Disallowed based on user tier |
#### 408 Request Timeout
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 408 | 40801 | REQUEST_TIMEOUT:Request has timed out |
#### 429 Too Many Requests
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 429 | 42901 | TOO_MANY_REQUESTS:Requests have exceeded rate limits |
#### 500 Internal Server Error
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 500 | 201 | NO_POSITION:No position |
| 500 | 203 | ACCOUNTS_DO_NOT_MATCH:Accounts do not match |
| 500 | 205 | DUPLICATE_ORDERID:Duplicate order id |
| 500 | 206 | INSTRUMENT_EXPIRED:Instrument has expired |
| 500 | 210 | INVALID_ACCOUNT:Account is invalid |
| 500 | 211 | INVALID_CURRENCY:Currency is invalid |
| 500 | 212 | INVALID_ORDERID:Invalid order id |
| 500 | 214 | INVALID_SETTLE_CURRENCY:Invalid settlement currency |
| 500 | 215 | INVALID_FEE_CURRENCY:Invalid fee currency |
| 500 | 216 | INVALID_POSITION_QTY:Invalid position quantity |
| 500 | 217 | INVALID_OPEN_QTY:Invalid open quantity |
| 500 | 219 | INVALID_EXECINST:Invalid exec_inst |
| 500 | 301 | ACCOUNT_IS_IN_MARGIN_CALL:Account is in margin call |
| 500 | 302 | EXCEEDS_ACCOUNT_RISK_LIMIT:Exceeds account risk limit |
| 500 | 303 | EXCEEDS_POSITION_RISK_LIMIT:Exceeds position risk limit |
| 500 | 304 | ORDER_WILL_LEAD_TO_IMMEDIATE_LIQUIDATION:Order will lead to immediate liquidation |
| 500 | 305 | ORDER_WILL_TRIGGER_MARGIN_CALL:Order will trigger margin call |
| 500 | 306 | INSUFFICIENT_AVAILABLE_BALANCE:Insufficient available balance |
| 500 | 307 | INVALID_ORDSTATUS:Invalid order status |
| 500 | 309 | MARKET_IS_NOT_OPEN:Market is not open |
| 500 | 310 | ORDER_PRICE_BEYOND_LIQUIDATION_PRICE:Order price beyond liquidation price |
| 500 | 311 | POSITION_IS_IN_LIQUIDATION:Position is in liquidation |
| 500 | 312 | ORDER_PRICE_GREATER_THAN_LIMITUPPRICE:Order price is greater than the limit up price |
| 500 | 313 | ORDER_PRICE_LESS_THAN_LIMITDOWNPRICE:Order price is less than the limit down price |
| 500 | 316 | NO_ACTIVE_ORDER:No active order |
| 500 | 317 | POSITION_NO_EXIST:Position does not exist |
| 500 | 320 | EXCEEDS_INITIAL_MARGIN:Exceeds initial margin |
| 500 | 321 | EXCEEDS_MAX_AVAILABLE_BALANCE:Exceeds maximum available balance |
| 500 | 406 | ACCOUNT_IS_NOT_ACTIVE:Account is not active |
| 500 | 407 | MARGIN_UNIT_DOES_NOT_EXIST:Margin unit does not exist |
| 500 | 409 | INVALID_USER:Invalid user |
| 500 | 410 | USER_IS_NOT_ACTIVE:User is not active |
| 500 | 411 | USER_NO_DERIV_ACCESS:User does not have derivative access |
| 500 | 412 | ACCOUNT_NO_DERIV_ACCESS:Account does not have derivative access |
| 500 | 415 | BELOW_MIN_ORDER_SIZE:Below Min. Order Size |
| 500 | 501 | EXCEED_MAXIMUM_EFFECTIVE_LEVERAGE:Exceeds maximum effective leverage |
| 500 | 604 | INVALID_COLLATERAL_PRICE:Invalid collateral price |
| 500 | 605 | INVALID_MARGIN_CALC:Invalid margin calculation |
| 500 | 606 | EXCEED_ALLOWED_SLIPPAGE:Exceed allowed slippage |
| 500 | 613 | INVALID_ISOLATION_ID:Invalid isolation ID |
| 500 | 614 | EXCEEDS_ISOLATED_POSITION_LIMIT:Exceeds maximum allowed number of isolated position |
| 500 | 615 | ACCOUNT_DOES_NOT_SUPPORT_ISOLATED_POSITION:Account does not support isolated position |
| 500 | 616 | CREATE_ISOLATED_POSITION_FAILED:Failed to create isolated position |
| 500 | 617 | DUPLICATED_INSTRUMENT_ORDER_FOR_ISOLATED_MARGIN:Account already have isolated position with same instrument |
| 500 | 618 | TOO_MANY_PENDING_ISOLATED_MARGIN_REQUESTS:Exceeds request limit for isolated margin order |
| 500 | 619 | UNSUPPORTED_OPERATION_ON_ISOLATED_POSITION:Unsupported operation on isolated position |
| 500 | 620 | CREATE_ISOLATED_POSITION_TIMEOUT:Request for create isolated position has timed out |
| 400 | 1110 | REDUCE_ONLY_REJECTED:Rejected REDUCE_ONLY create-order request |
| 500 | 43003 | FILL_OR_KILL:FOK order has not been filled and cancelled |
| 500 | 43004 | IMMEDIATE_OR_CANCEL:IOC order has not been filled and cancelled |
| 500 | 43005 | POST_ONLY_REJ:Rejected POST_ONLY create-order request (normally happened when exec_inst contains POST_ONLY but time_in_force is NOT GOOD_TILL_CANCEL) |
| 500 | 120009 | REJECTED:Request rejected by upstream service |
| 500 | 130008 | NON_APPLICABLE:Operation not applicable for current state |
### 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 |
### 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.
### Common Issues
#### TOO_MANY_REQUESTS After Websocket Connects
Websocket rate limits are pro-rated based on the calendar-second that the websocket connection was opened.
This means, depending on the fraction of the calendar-second that the connection was established, the rate limit could be pro-rated to a small number.
By adding a 1-second sleep after establishing the websocket connection, and before requests are sent, this will ensure the rate limit is properly reset and sync'd to your session.
This will avoid occurrences of rate-limit (TOO_MANY_REQUESTS) errors.
#### INVALID_NONCE On All Requests
The nonce should be the UTC Unix timestamp in milliseconds.
If this has been carefully checked, then the issue occurs when the system clock of the client machine is greater than 60 seconds in the future / past.
Usually, re-syncing with the NTP time server on the client machine will correct the issue.
If the issue persists, you can try deliberately subtracting N seconds from the nonce to force it to be N seconds in the past, which is still within the 60-second past tolerance.
---
## OTC RFQ for Taker(Websocket)
## RFQ Trading Flow
1. Taker can firstly subscribe to the following WebSocket channels:
- [`user.otc_qr.requests`](/docs/api/websocket/ws-channel-user-otc-qr-requests)
- [`user.otc_qr.quotes`](/docs/api/websocket/ws-channel-user-otc-qr-quotes)
- [`user.otc.deals`](/docs/api/websocket/ws-channel-user-otc-deals)
2. Taker can create a quote request via WebSocket: [`private/otc/request-quote`](/docs/api/websocket/ws-user-api-private-otc-request-quote-rfq)
3. Taker, who will be notified of quotes from the WebSocket channel [`user.otc_qr.quotes`](/docs/api/websocket/ws-channel-user-otc-qr-quotes), can create a deal request upon Quote message with [`private/otc/request-deal`](/docs/api/rest/private-otc-request-deal-rfq)
4. Taker will receive confirmation of the deal's status on WebSocket channel [`user.otc.deals`](/docs/api/websocket/ws-channel-user-otc-deals)
5. Taker can get the rejected or completed quote request from [Quote Query API](/docs/api/rest/private-otc-get-quote-request-history)
6. Taker can get the rejected or completed deal from [Deal Query API](/docs/api/rest/private-otc-get-deal-history-rfq)
## Quote Request Lifecycle
| Status | Description |
|--------|-------------|
| `ACTIVE` | user may receive a quote and user may call request-deal to execute a trade |
| `COMPLETED` | quote request duration has expired and no longer valid. User will not receive quote nor able to call request-deal anymore |
| `REJECTED` | rejected due to various reasons; quote request is no longer valid |
## Quote Lifecycle
| Status | Description |
|--------|-------------|
| `ACTIVE` | Quote is valid |
| `EXPIRED` | Quote has exceeded its TTL |
| `CANCELLED` | Liquidity provider cancelled the quote |
## Deal History
Use the deal history endpoint to retrieve executed trades. Deal statuses:
| Status | Description |
|--------|-------------|
| `ACCEPTED` | Deal request accepted by the system. |
| `CONFIRMED` | Liquidity provider has executed the deal. |
| `SETTLED` | Deal settled and funds transferred. |
| `REJECTED` | Deal request rejected (quote expired, insufficient balance, etc.) |
---
## Trading(Websocket)
Private trading endpoints manage order placement and lifecycle. All order operations (create, amend, cancel) are asynchronous — the REST response confirms the request was received, but order lifecycle updates arrive via WebSocket subscriptions.
## Order Management Workflow
**Create Order**
Call `private/create-order` to submit a new order. The response returns an `order_id` and `client_oid`, but the order may still be pending acceptance by the matching engine. Subscribe to `user.order` or `user.order.{instrument_name}` to receive real-time order status updates.
**Amend Order**
Call [`private/amend-order`](/docs/api/rest/private-amend-order) to modify price or quantity on an existing order. Behind the scenes, amend performs a cancel-then-create operation. The new order loses queue priority unless you are only reducing quantity.
**Cancel Order**
Call [`private/cancel-order`](/docs/api/rest/private-cancel-order) to cancel a single order by `order_id` or `client_oid`, or [`private/cancel-all-orders`](/docs/api/rest/private-cancel-all-orders) to cancel all orders for a given instrument.
## Order Types
| Type | Description |
|------|-------------|
| `LIMIT` | Limit order with specified price. Rests on the order book until filled or canceled. |
| `MARKET` | Market order that executes immediately at best available price. |
For trigger orders (stop-loss, take-profit) and multi-leg strategies (OCO, OTO, OTOCO), see [Advanced Order Management](/docs/api/rest/advanced-order-management).
## Time in Force
| Value | Description |
|-------|-------------|
| `GOOD_TILL_CANCEL` | Order remains active until filled or explicitly canceled. Default for limit orders. |
| `IMMEDIATE_OR_CANCEL` | Order fills immediately (partial or full), unfilled portion is canceled. |
| `FILL_OR_KILL` | Order must fill entirely and immediately, or the entire order is canceled. |
## Execution Instructions
Execution instructions are passed as an array in `exec_inst`. Multiple instructions can be combined.
| Instruction | Description |
|-------------|-------------|
| `POST_ONLY` | Order is rejected if it would take liquidity. Ensures maker fee. |
| `SMART_POST_ONLY` | If the order would take liquidity, it is repriced to the best maker level instead of being rejected. |
| `REDUCE_ONLY` | Order can only reduce an existing position, not increase or open a new position. |
## Order Statuses
| Status | Description |
|--------|-------------|
| `PENDING` | Order submitted, awaiting processing by the matching engine. |
| `NEW` | Order accepted by the matching engine, not yet on the order book. |
| `ACTIVE` | Order is live on the order book, waiting to be filled. |
| `FILLED` | Order has been completely filled. |
| `CANCELED` | Order was canceled (by user request, or by system). |
| `EXPIRED` | Order expired due to time-in-force constraints. |
| `REJECTED` | Order was rejected (e.g., invalid parameters, risk checks failed). |
## Querying Orders and Trades
- [`private/get-open-orders`](/docs/api/rest/private-get-open-orders) — retrieve all currently active orders
- [`private/get-order-detail`](/docs/api/rest/private-get-order-detail) — fetch detailed information about a single order
- [`private/get-order-history`](/docs/api/rest/private-get-order-history) — retrieve past orders (filled, canceled, or rejected)
- [`private/get-trades`](/docs/api/rest/private-get-trades) — retrieve executed trades (fills)
## Real-Time Order and Trade Updates
Subscribe to the following WebSocket channels for real-time updates:
| Channel | Description |
|---------|-------------|
| `user.order` | Order lifecycle events across all instruments |
| `user.order.{instrument_name}` | Order updates for a specific instrument |
| `user.trade` | Trade execution events across all instruments |
| `user.trade.{instrument_name}` | Trade execution events for a specific instrument |
These subscriptions require authentication and eliminate the need for polling REST endpoints.
---
## Websocket Market Data
---
## Websocket User API
---
## book.{instrument_name}.{depth}
book.{"{instrument_name}"}.{"{depth}"} Order book (L2). Subscribe with channels e.g. ["book.BTCUSD-PERP.10"] or ["book.BTCUSD-PERP.50"].
Optional params: book_subscription_type (SNAPSHOT | SNAPSHOT_AND_UPDATE), book_update_frequency (10 | 100 | 500 ms).
## Request
---
## candlestick.{timeframe}.{instrument_name}
candlestick.{"{timeframe}"}.{"{instrument_name}"} Candlestick (k-line) updates. Subscribe e.g. ["candlestick.1D.BTCUSD-PERP"]. Timeframe: 1m, 5m, 15m, 30m, 1h, 2h, 4h, 12h, 1D, 7D, 14D, 1M.
## Request
---
## estimatedfunding.{instrument_name}
estimatedfunding.{"{instrument_name}"} Estimated funding rate for the next interval. Subscribe e.g. ["estimatedfunding.BTCUSD-PERP"].
Refers to estimated hourly rate that will be effective at the end of each hour in the next interval.
Funding intervals are 00:00 - 04:00, 04:00 - 08:00, 08:00 - 12:00, 12:00 - 16:00, 16:00 - 20:00, 20:00 - 00:00 UTC
## Request
---
## funding.{instrument_name}
funding.{"{instrument_name}"} Hourly funding rate that will settle at end of current hour. Subscribe e.g. ["funding.BTCUSD-PERP"].
## Request
---
## index.{instrument_name}
index.{"{instrument_name}"} Index price. Subscribe e.g. ["index.BTCUSD-INDEX"].
## Request
---
## mark.{instrument_name}
mark.{"{instrument_name}"} Mark price (updates ~50ms). Subscribe e.g. ["mark.BTCUSD-PERP"].
## Request
---
## settlement.{instrument_name}
settlement.{"{instrument_name}"} Settlement prices. Subscribe e.g. ["settlement.BTCUSD-210528"] or wildcard.
## Request
---
## ticker.{instrument_name}
ticker.{"{instrument_name}"} Ticker updates. Subscribe with channels e.g. ["ticker.BTCUSD-PERP"].
## Request
---
## trade.{instrument_name}
trade.{"{instrument_name}"} Public trades. Subscribe with channels e.g. ["trade.BTCUSD-PERP"]. Returns last 50 trades on subscribe.
## Request
---
## user.account_risk
user.account_risk Account risk snapshot on a regular basis. Subscribe with channels ["user.account_risk"].
## Request
---
## user.advance.order.{instrument_name}
user.advance.order.{"{instrument_name}"} OTO/OTOCO order updates. Subscribe with channel ["user.advance.order.{"{instrument_name}"}"].
## Request
---
## user.advance.order
user.advance.order OTO/OTOCO order updates. Subscribe with channel ["user.advance.order"].
## Request
---
## user.balance
user.balance Balance updates. Subscribe with channels ["user.balance"].
## Request
---
## user.order.{instrument_name}
user.order.{"{instrument_name}"} Order updates for the user. Subscribe with channel ["user.order.{"{instrument_name}"}"].
Initial response with same id contains current open orders for the instrument; subsequent messages (id -1) are live updates.
## Request
---
## user.order
user.order Order updates for the user. Subscribe with channel ["user.order"].
Initial response with same id contains current open orders; subsequent messages (id -1) are live updates.
## Request
---
## user.otc.deals
user.otc.deals OTC deal updates for RFQ takers. Subscribe with channels ["user.otc.deals"].
Provides deal status updates (ACCEPTED, CONFIRMED, SETTLED, REJECTED).
## Request
---
## user.otc_qr.quotes
user.otc_qr.quotes OTC quote updates for RFQ takers. Subscribe with channels ["user.otc_qr.quotes"].
Receives quotes with bid/ask prices in response to quote requests.
## Request
---
## user.otc_qr.requests
user.otc_qr.requests OTC quote request status updates for RFQ takers. Subscribe with channels ["user.otc_qr.requests"].
Provides quote_req_id after request-quote, then status updates (ACTIVE, REJECTED, COMPLETED).
## Request
---
## user.position_balance
user.position_balance Position and balance realtime updates. Subscribe with channels ["user.position_balance"].
## Request
---
## user.positions
user.positions Position updates. Subscribe with channels ["user.positions"].
## Request
---
## user.trade.{instrument_name}
user.trade.{"{instrument_name}"} Trade updates for the user. Subscribe with channel ["user.trade.{"{instrument_name}"}"].
## Request
---
## user.trade
user.trade Trade updates for the user. Subscribe with channel ["user.trade"].
## Request
---
## user.transactions
user.transactions Transaction updates for the user. Subscribe with channel ["user.transactions"].
## Request
---
## private/get-cancel-on-disconnect
private/get-cancel-on-disconnect Get cancel on disconnect
## Request
---
## public/heartbeat
public/heartbeat Heartbeat sent by server every 30s; client must respond with public/respond-heartbeat within 5 seconds.
## Request
---
## public/auth
public/auth Authenticate with API key and signature (required once per User API session)
## Request
---
## public/respond-heartbeat
public/respond-heartbeat Respond to server heartbeat within 5 seconds
## Request
---
## private/set-cancel-on-disconnect
private/set-cancel-on-disconnect Set cancel on disconnect
## Request
---
## subscribe
subscribe Subscribe to one or more **user** channels. Use on the User API server only.
## Request
---
## unsubscribe
unsubscribe Unsubscribe from user channels. Use on the User API server only.
## Request
---
## public/heartbeat(Websocket)
public/heartbeat Heartbeat sent by server every 30s; client must respond with public/respond-heartbeat within 5 seconds.
## Request
---
## subscribe(Websocket)
subscribe Subscribe to one or more **market data** channels. Use on the Market Data server only.
## Request
---
## unsubscribe(Websocket)
unsubscribe Unsubscribe from market data channels. Use on the Market Data server only.
## Request
---
## public/respond-heartbeat(Websocket)
public/respond-heartbeat Respond to server heartbeat within 5 seconds
## Request
---
## private/advanced/amend-order(Websocket)
private/advanced/amend-order Amends an existing trigger order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the order is successfully amended.
**Trigger Order Type Conversion:**
- Set `new_price` to "0" → Convert trigger limit order to trigger market order
- Set `new_price` to "> 0" → Convert trigger market order to trigger limit order
## Request
---
## private/advanced/cancel-all-orders(Websocket)
private/advanced/cancel-all-orders Cancels all OTO/OTOCO orders for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advance.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/advanced/cancel-oco(Websocket)
private/advanced/cancel-oco Cancel an OCO order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
## Request
---
## private/advanced/cancel-order-list(Websocket)
private/advanced/cancel-order-list Cancels multiple advanced orders in a single request.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the orders are successfully canceled.
## Request
---
## private/advanced/cancel-order(Websocket)
private/advanced/cancel-order Cancel an individual order of a OTO/OTOCO order on the Exchange (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advance.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/advanced/cancel-oto(Websocket)
private/advanced/cancel-oto Cancel a SPOT_ATTACH or DERIV_ATTACH order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
**Note:** This API can also be used to cancel SpotAttach / DerivAttach orders regardless of the number of legs (2 or 3). Both `cancel-oto` and `cancel-otoco` can be used interchangeably to cancel SpotAttach / DerivAttach orders by `list_id`.
## Request
---
## private/advanced/cancel-otoco(Websocket)
private/advanced/cancel-otoco Cancel a SPOT_ATTACH or DERIV_ATTACH order on the Exchange. This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check when each of the orders is successfully cancelled.
**Note:** This API can also be used to cancel SpotAttach / DerivAttach orders regardless of the number of legs (2 or 3). Both `cancel-oto` and `cancel-otoco` can be used interchangeably to cancel SpotAttach / DerivAttach orders by `list_id`.
## Request
---
## private/advanced/create-oco(Websocket)
private/advanced/create-oco Creates a One-cancels-the-Other (OCO) execution strategy on the Exchange.
OCO execution strategy allows users to place a two-order strategy where one order automatically cancels the other when one of the orders is partially/fully executed. Users are able to place 2 orders - one LIMIT and one trigger order. Only one of the orders will be executed. The trigger order can either be a stop loss or take profit order. The OCO order type is only available for Spot trading pairs for now.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT`, the other order must be `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT` or `TAKE_PROFIT`. For `ref_price_type` of the trigger order, only `MARK_PRICE` is supported for now.
## Request
---
## private/advanced/create-order-list(Websocket)
private/advanced/create-order-list Creates multiple advanced orders in a single request.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check when the orders are successfully created.
## Request
---
## private/advanced/create-order(Websocket)
private/advanced/create-order Creates a new BUY or SELL trigger order on the Exchange.
`type` must be STOP_LOSS, STOP_LIMIT, TAKE_PROFIT or TAKE_PROFIT_LIMIT.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.advanced.order` subscription can be used to check if the orders are successfully created.
**Helpful information:**
- STOP_LIMIT and TAKE_PROFIT_LIMIT will execute a LIMIT order when the ref_price is reached.
- STOP_LOSS and TAKE_PROFIT will execute a MARKET order when the ref_price is reached.
**To create trigger orders based on ref_price vs. the reference price (ref_price_type):**
- ref_price below ref_price_type price: SELL STOP_LOSS and STOP_LIMIT, BUY TAKE_PROFIT and TAKE_PROFIT_LIMIT
- ref_price above ref_price_type price: BUY STOP_LOSS and STOP_LIMIT, SELL TAKE_PROFIT and TAKE_PROFIT_LIMIT
**SpotAttach / DerivAttach:**
- **Contingency type resolution**: Automatically resolved from instrument type - spot instruments → SPOT_ATTACH, derivative instruments → DERIV_ATTACH
- **DerivAttach attach-to-order**: Use `attach_order_id` to attach TP/SL to an existing limit order
- **DerivAttach attach-to-position**: Use `attach_isolation_id` to attach TP/SL directly to an existing position (\> 0 for isolated position ID, 0 for cross-margin position). Requires REDUCE_ONLY in exec_inst.
- **Standalone TP/SL**: For derivatives, if neither `attach_order_id` nor `attach_isolation_id` is specified, isolation is resolved from `isolation_id` parameter (if provided) or defaults to cross-margin
## Request
---
## private/advanced/create-oto(Websocket)
private/advanced/create-oto Creates a One-triggers-the-Other (OTO) execution strategy on the Exchange.
OTO execution strategy allows users to place a two-order strategy where one order automatically triggers the other when the first order is fully executed. Users are able to place a limit or market order with a trigger order, and only when the primary order is fully executed, the trigger order will take effect. The trigger order can either be a stop loss or take profit order.
**SpotAttach / DerivAttach:** This API creates SpotAttach (for spot instruments) or DerivAttach (for derivative instruments) order types. The contingency type is automatically resolved from the instrument type. With 2 legs (1 limit/market + 1 trigger), it follows OTO behavior.
- **SpotAttach**: Flexible - you can later attach additional TP/SL using `private/advanced/create-order` with `attach_order_id`, effectively converting it to OTOCO behavior. You can also cancel individual legs using `private/advanced/cancel-order` and reattach new ones.
- **DerivAttach**: For derivatives, the primary leg may specify `isolation_id`, `leverage`, `isolated_margin_amount`, and `exec_inst` may include ISOLATED_MARGIN. Trigger legs inherit the isolation mode from the parent leg.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT` or `MARKET`, and the other must be `STOP_LOSS`, `STOP_LIMIT`, `TAKE_PROFIT_LIMIT` or `TAKE_PROFIT`. The `ref_price_type` for the trigger order supports `MARK_PRICE` (default), `INDEX_PRICE`, and `LAST_PRICE`.
## Request
---
## private/advanced/create-otoco(Websocket)
private/advanced/create-otoco Creates a One-Triggers-a-One-Cancels-the-Other (OTOCO) execution strategy on the Exchange.
OTOCO execution strategy allows users to place a three-order strategy where one order automatically triggers the other two when the first order is fully executed. Users are able to place a limit or market order with two trigger orders, and only when the primary order is fully executed, the two trigger orders will take effect. The two trigger orders must be one stop loss and one take profit orders.
**SpotAttach / DerivAttach:** This API creates SpotAttach (for spot instruments) or DerivAttach (for derivative instruments) order types. The contingency type is automatically resolved from the instrument type. With 3 legs (1 limit/market + 2 triggers), it follows OTOCO behavior.
- **SpotAttach**: When either one of the two trigger orders is executed, the other is automatically canceled (OCO behavior). SpotAttach orders are flexible - you can cancel one of the TP/SL legs using `private/advanced/cancel-order`, effectively converting it to OTO behavior. You can also reattach new TP/SL using `private/advanced/create-order` with `attach_order_id`.
- **DerivAttach**: For derivatives, the two trigger legs are independent - one firing does NOT cancel the other (unlike SpotAttach). The primary leg may specify `isolation_id`, `leverage`, `isolated_margin_amount`, and `exec_inst` may include ISOLATED_MARGIN. Trigger legs inherit the isolation mode from the parent leg.
This call is asynchronous, so the response is simply a confirmation of the request. The `user.advanced.order` subscription can be used to check if the orders are successfully created.
For the content of each order in order_list, please refer to `private/create-order` for details. One order must be `LIMIT` or `MARKET`, and for the two trigger orders, one must be `STOP_LOSS` or `STOP_LIMIT`, and the other one must be `TAKE_PROFIT` or `TAKE_PROFIT_LIMIT`. The `ref_price_type` for the trigger orders supports `MARK_PRICE` (default), `INDEX_PRICE`, and `LAST_PRICE`.
## Request
---
## private/amend-order(Websocket)
private/amend-order Amend an existing order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The user.order subscription can be used to check when the order is successfully created.
Please note that amend order is designed as a convenience function such that it performs cancel and then create behind the scene. The new order will lose queue priority, except if the amend is only to amend down order quantity.
## Request
---
## private/batch-order-request
private/batch-order-request A batched order operation endpoint that allows you to submit multiple cancel and create order operations in a single request for a specific instrument.
Cancels are processed before creates (not atomic by default). Operations are independent (one failure doesn't roll back others) when atomic is false.
**Limits:**
- Maximum 10 create orders per batch request
- At least one of cancels or creates must be non-empty
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when orders are successfully created or canceled.
## Request
---
## private/cancel-all-orders(Websocket)
private/cancel-all-orders Cancels all orders for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/cancel-order-list (LIST)(Websocket)
private/cancel-order-list (LIST) Cancel a list of orders on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when each of the orders is successfully cancelled.
## Request
---
## private/cancel-order(Websocket)
private/cancel-order Cancels an existing order on the Exchange.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/close-position(Websocket)
private/close-position Cancels position for a particular instrument/pair (asynchronous).
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully canceled.
## Request
---
## private/create-order(Websocket)
private/create-order Creates a new BUY or SELL order.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check when the order is successfully created.
## Request
---
## private/create-order-list (LIST)(Websocket)
private/create-order-list (LIST) Create a list of orders on the Exchange.
`contingency_type` must be LIST, for list of orders creation.
This call is asynchronous, so the response is simply a confirmation of the request.
The `user.order` subscription can be used to check if the orders are successfully created.
## Request
---
## private/otc/request-deal (RFQ)(Websocket)
private/otc/request-deal (RFQ) Request a deal from a quote (RFQ flow).
## Request
---
## private/otc/request-quote (RFQ)(Websocket)
private/otc/request-quote (RFQ) Create a quote request (RFQ flow).
## Request
---
## Breaking Change Schedule(Api)
- On 2025-12-17 8:00 UTC,
The current trigger order creation/cancellation will be migrated to Advanced Order Management API.
- On 2025-02-27 8:00 UTC,
For `book.{instrument_name}.{depth}`, the full snapshot subscription (`book_subscription_type=SNAPSHOT`) `100ms` frequency is removed.
Customers wishing to continue with the faster `100ms` frequency should switch to the delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`).
This higher performing subscription benefits the user with reduced bandwidth/processing compared to the snapshot subscription.
For a transition period, users subscribing to the removed `100ms` snapshot will receive the `500ms` subscription.
The `book.{instrument_name}` subscription (default depth) will be removed.
Customers should use the explicit `book.{instrument_name}.{depth}` subscription and specify the required depth.
For a transition period, users subscribing to the removed subscription will receive the default `50` depth subscription.
- These changes will take place around 17 December 2023 8:00 UTC.
- Market Data wildcard ticker subscription will be removed. Users should use the instrument specific subscription.
---
## Change Log(3)
- **2026-05-21**
- `public/get-instruments` response updated, new field `product_type` was added
- Trading Bot API section was added:
`private/bot/create-trading-bot` (DCA, TWAP, GRID, FUNDING_ARBITRAGE)
`private/bot/terminate-trading-bot`
`private/bot/update-trading-bot`
`private/bot/pause-trading-bot`
`private/bot/resume-trading-bot`
`private/bot/get-trading-bots`
`private/bot/get-trading-bot-executions`
- **2026-05-07**
- Advanced Order Management API section was updated for DerivAttach
- `private/advanced/create-oto` and `private/advanced/create-otoco` — contingency type is now resolved from instrument type: spot instruments create SPOT_ATTACH, derivative instruments create DERIV_ATTACH. DerivAttach supports `isolation_id`, `leverage`, `isolated_margin_amount` on the primary leg and `ISOLATED_MARGIN` in `exec_inst`. Trigger legs inherit isolation mode from the parent.
- `private/advanced/create-order` — `attach_order_id` now applies to both SpotAttach and DerivAttach. New optional field `attach_isolation_id` for DerivAttach attach-to-position (derivatives only).
- `private/advanced/cancel-oto` and `private/advanced/cancel-otoco` — updated to cover both SPOT_ATTACH and DERIV_ATTACH.
- `private/advanced/cancel-all-orders` — new optional field `position_type` (CROSS_MARGIN, ISOLATED_MARGIN).
- `private/advanced/get-open-orders`, `private/advanced/get-order-detail`, `private/advanced/get-order-history`, and `user.advance.order` — response attributes extended with `exchange_order_id`, `ref_price`, `ref_price_type`, `reject_reason`, `attach_isolation_id`, `isolation_id`, `isolation_type`, `leverage`, `isolated_margin_amount`. `contingency_type` now includes DERIV_ATTACH.
- `private/advanced/amend-order` — corrected required/optional flags: `new_price` is Y, `new_quantity` is Y, `new_ref_price` is N.
- **2026-04-29**
- Fee Credits
- `private/get-fee-credit-balances` was added
- `private/get-trades` response updated, new field `fee_credits` was added
- `user.trade.{instrument_name}` response updated, new field `fee_credits` was added
- **2026-04-07**
- `private/get-accounts` response updated, new field `hierarchy` was added
- **2026-04-01**
- `private/create-order` request updated, `REDUCE_ONLY` was added to `exec_inst`
- **2026-01-08**
- Add support for isolated position
- `private/create-isolated-margin-transfer` was added
- `private/change-isolated-margin-leverage` was added
- `private/user-balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/user-balance-history` response updated, new field `i` was added
- `private/get-subaccount-balances` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `private/get-positions` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/create-order` request updated, new optional fields `isolation_id`, `leverage`, `isolated_margin_amount` were added, `exec_inst` added support for `ISOALTED_MARGIN`
- `private/close-position` request updated, new optional field `isolation_id` was added
- `private/get-open-orders` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-detail` response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-order-history` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-trades` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `private/get-transactions` request updated, new optional field `isolation_id` was added, response updated, new fields `isolation_id` and `isolation_type` were added
- `user.order.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.trade.{instrument_name}` response updated, new fields `isolation_id` and `isolation_type` were added
- `user.balance` response updated, new fields `total_isolated_cash_balance` and `isolated_positions` were added
- `user.positions` response updated, new fields `isolation_id`, `leverage`, `isolation_type`, `liquidation_price` and `isolated_margin_balance` were added
- `user.account_risk` response updated, new fields `total_isolated_cash_balance`, `isolated_positions` were added
- `user.position_balance` response updated, new field `isolated_positions` was added
- **2025-03-26**
- `transaction_time` was added into `user.order.{instrument_name}`
- **2025-11-18**
- `public/get-risk-parameters` was added new columns
- **2025-10-16**
- `Advanced Order Management API` section was updated
- **2025-07-17**
- `private/fiat/fiat-deposit-info` was added
- `private/fiat/fiat-deposit-history` was added
- `private/fiat/fiat-withdraw-history` was added
- `private/fiat/fiat-create-withdraw` was added
- `private/fiat/fiat-get-bank-accounts` was added
- `private/fiat/fiat-transaction-quota` was added
- `private/fiat/fiat-transaction-limit` was added
- **2025-07-04**
- `private/create-order` exec_inst was added `SMART_POST_ONLY`
- `private/create-order-list (LIST)` exec_inst was added `SMART_POST_ONLY`
- `private/get-open-orders` exec_inst was added `SMART_POST_ONLY`
- `private/get-order-detail` was added, exec_inst was added `SMART_POST_ONLY`
- `private/get-order-history` exec_inst was added `SMART_POST_ONLY`
- **2025-06-10**
- `private/amend-order` was added
- `public/get-announcements` was added
- **2025-05-29**
- transaction_time_ns field was added into `user.order.{instrument_name}` response
- **2025-03-14**
- Removed deprecated attributes system_label in `private/get-accounts`
- **2025-03-06**
- Removed deprecated `book.{instrument_name}` default book subscription
- Removed deprecated 100ms interval from full snapshot `book.{instrument_name}.{depth}` book subscription
- **2025-03-04**
- Remove section: `Unified Wallet and System Label`
- **2025-01-27**
- `book.{instrument_name}.{depth}` - The following additional update frequencies are now supported:
Full snapshot subscription (`book_subscription_type=SNAPSHOT`) `500ms`
Delta subscription (`book_subscription_type=SNAPSHOT_AND_UPDATE`) `100ms`
- **2024-12-11**
- `private/create-order` fee_instrument_name was added
- **2024-10-02**
- `public/get-risk-parameters` was added
- **2024-08-15**
- `private/get-fee-rate` was added
- `private/get-instrument-fee-rate` was added
- **2024-07-12**
- Staking API added:
`private/staking/stake`
`private/staking/unstake`
`private/staking/get-staking-position`
`private/staking/get-staking-instruments`
`private/staking/get-open-stake`
`private/staking/get-stake-history`
`private/staking/get-reward-history`
`private/staking/convert`
`private/staking/get-open-convert`
`private/staking/get-convert-history`
`public/staking/get-conversion-rate`
- **2024-06-27**
- `private/create-order` self-trade prevent (STP) was added
- `private/create-order-list (LIST)` self-trade prevent (STP) was added
- **2024-02-12**
- `public/get-trades`, `trade.{instrument_name}` subscription, clarification for the public trade side field
- Side is the side of the taker order
- `book.{instrument_name}.{depth}` clarifications for book delta sequence number handling and re-subscription
- **2024-01-04**
- Market data websocket subscription enhancements:
- `book.{instrument_name}` - The `subscription` result value is now explicit
e.g. previous `"subscription": "book.BTC_USD"` -> new `"subscription": "book.BTC_USD.50"`
- `book.{instrument_name}.{depth}` - For delta updates, the fixed 500ms delta full book snapshot heartbeat is replaced with empty delta in the case of no book changes
- `ticker` - Documented existing 'bs' and 'ks' fields (bid/ask size)
- `settlement` - For wildcard subscription, the `subscription` result value is now explicit
e.g. previous `"subscription": "settlement"` -> new `"subscription": "settlement.BTCUSD-231124"`
- Applied consistent field ordering for all market data subscriptions (`book`, `ticker`, `trade`, `candlestick`, `index`, `mark`, `settlement`, `funding`, `estimatedfunding`).
Result fields are always in the following order:
`id, method, code, instrument_name, subscription, channel`
- Market data REST `public/get-trades`
- Added additional `tn` nanoseconds timestamp field to the trade response
- Clarified timestamp pagination parameters
- **2023-12-18**
- Market Data wildcard ticker subscription removed. Users should use the instrument specific subscription.
- **2023-12-11**
- Introduced Market Data subscription limiting. Refer to Market Data Websocket Subscription Limits for more details
- **2023-10-31**
- `user.balance`, `private/user-balance` will be updated:
1. Existing field total_margin_balance will represent new margin balance calculation without haircut.
2. Existing field total_initial_margin previously is made up of position IM only. On effective date, this field will represent the total sum of total_position_im + total_haircut
3. New field total_position_im will be introduced to represent initial margin requirement to support open positions and orders
4. New field total_haircut will be introduced to represent the total haircut on eligible collateral token assets. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- `user.balance`, `user.account_risk`, `private/user-balance`, `private/get-subaccount-balances` will be updated:
1. New field collateral_eligible will be introduced to indicate if token is eligible Collateral
2. collateral_weight will be deprecated
3. New field haircut will be introduced to show haircut of eligible collateral token instead of collateral Weight. Refer to [Smart Cross Margin Enhancement Guide](https://static2.crypto.com/exchange/assets/documents/Exchange%20Smart%20Cross%20Margin%20Enhancement%20Guide%202023.pdf) for details
- **2023-08-11**
- `private/create-order-list (LIST)` for batch order creation added
- `private/cancel-order-list (LIST)` for batch order cancel added
- **2023-07-31**
- Market Data Websocket Subscriptions is effective:
- `funding.{instrument_name}` - channel will return the fixed hourly rate that will settle at the end of the hour.
- `estimatedfunding.{instrument_name}` - channel will return the estimated hourly rate that will begin in the next interval.
- Added new "funding_rate" and "estimated_funding_rate" valuation types for public/get-valuations
- **2023-06-28**
- `private/get-deposit-history` added
- `private/get-withdrawal-history` added
- **2022-11-30**
- Support using `client_oid` to query in `private/get-order-detail` REST API
- **2022-11-10**
- `USD_Stable_Coin` (aka USD Bundle), will be renamed as `USD`. Customer can test the change in UAT from 2022-11-10 before the change is effective in PROD. Target date for PROD is TBD.
- Customer can input both `USD` and `USD_Stable_Coin` to mean the same USD Bundle.
- However, on response, `USD` will be used to mean USD Bundle, instead of `USD_Stable_Coin`.
- **2022-10-31**
- Added `private/create-order-list`, `private/create-subaccount-transfer` REST APIs
- Added `user.account_risk` and `user.position_balance` WebSocket subscriptions
- Added more `period` in `public/get-candlestick` `candlestick.{time_frame}.{instrument_name}` WebSocket subscription
- **2022-09-21** - Added **Unified Wallet and System Label** section, to illustrate the transition from multiple wallets into unified wallet.
- **2022-09-21** - Added new sub-account management endpoints: `private/get-accounts`, `private/create-subaccount-transfer`
- **2022-09-21** - Added new exchange wallet management endpoints: `private/create-withdrawal`, `private/get-deposit-address`, `private/get-curency-networks`
- **2022-09-21** - First publish, based on Derivative Exchange API v1.
---
## Common API Reference(Api)
## Common API References
### Naming Conventions
- All **methods and URLs** in **dash-case**
- All **parameters** in **snake_case**
- **Enums** in full **UPPERCASE** and **snake_case**
### Generating the API Key
Before sending any requests, generate a new API key on the Exchange website under **User Center** → **API**. Note down:
- **API Key**
- **Secret Key**
Default settings are "Can Read" only; you can add or remove permissions via the Web UI. You may optionally specify a whitelist of IP addresses; if set, the API can only be used from those IPs.
### REST API Root Endpoints
REST API requests must be sent with **Content-Type: application/json**.
| Environment | REST API |
|-------------|----------|
| **UAT Sandbox** | `https://uat-api.3ona.co/exchange/v1/{method}` |
| **Production** | `https://api.crypto.com/exchange/v1/{method}` |
### Websocket Root Endpoints
| Environment | Websocket (User API) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/user` |
| **Production** | `wss://stream.crypto.com/exchange/v1/user` |
| Environment | Websocket (Market Data) |
|-------------|----------|
| **UAT Sandbox** | `wss://uat-stream.3ona.co/exchange/v1/market` |
| **Production** | `wss://stream.crypto.com/exchange/v1/market` |
### Rate Limits
#### REST API
For authenticated calls, rate limits are per API method, per API key:
| Method | Limit |
|--------|-------|
| `private/create-order`, `private/cancel-order`, `private/cancel-all-orders` | 15 requests per 100ms each |
| `private/get-order-detail` | 30 requests per 100ms |
| `private/get-trades` | 1 request per second |
| `private/get-order-history` | 1 request per second |
| All others | 3 requests per 100ms each |
For public market data calls, rate limits are per API method, per IP address:
| Method | Limit |
|--------|-------|
| All | 100 requests per second each |
#### Staking
| Method | Limit |
|--------|-------|
| All | 50 requests per second each |
#### Websocket
| Method | Limit |
|--------|-------|
| User API | 150 requests per second |
| Market Data | 100 requests per second |
### Request Format
The following information applies to both REST API and websockets commands:
| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | long | Y | Request identifier (0 to 9,223,372,036,854,775,807). Response echoes the same id. |
| method | string | Y | The method to be invoked (e.g. `private/get-order-detail`). |
| params | object | Y | Parameters for the method. Use `{}` when a method has no parameters. |
| api_key | string | Depends | API key. Required for **private** methods (see Digital Signature). |
| sig | string | Depends | Digital signature. Required for **private** methods. |
| nonce | long | Y | Current timestamp in **milliseconds** since the Unix epoch. |
**⚠️ All numbers must be strings, and must be wrapped in double quotes. e.g. "12.34", instead of 12.34.**
### Digital Signature
For REST API, only 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 pass in the digital signature and API key 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 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.
Besides, for JavaScript client calling `private/get-order-detail` API, it is highly recommended to use STRING format of `order_id` in the JSON request payload, in order to guarantee the correctness of Digital Signature.
#### JavaScript Example
```javascript
const crypto = require("crypto-js");
const signRequest = (request_body, api_key, secret) => {
const { id, method, params, nonce } = request_body;
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)); }, "");
}
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);
const sigPayload = method + id + api_key + paramsString + nonce;
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",
method: "private/get-order-detail",
api_key: apiKey,
params: {
order_id: "53287421324"
},
nonce: "1587846358253",
};
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));
```
#### Python Example
```python
API_KEY = "API_KEY"
SECRET_KEY = "SECRET_KEY"
req = {
"id": "14",
"method": "private/create-order-list",
"api_key": API_KEY,
"params": {
"contingency_type": "LIST",
"order_list": [
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "LIMIT",
"price": "0.24",
"quantity": "1.0"
},
{
"instrument_name": "ONE_USDT",
"side": "BUY",
"type": "STOP_LIMIT",
"price": "0.27",
"quantity": "1.0",
"trigger_price": "0.26"
}
]
},
"nonce": str(int(time.time() * 1000))
}
# First ensure the params are alphabetically sorted by key
param_str = ""
MAX_LEVEL = 3
def params_to_str(obj, level):
if level >= MAX_LEVEL:
return str(obj)
return_str = ""
for key in sorted(obj):
return_str += key
if obj[key] is None:
return_str += 'null'
elif isinstance(obj[key], list):
for subObj in obj[key]:
return_str += params_to_str(subObj, level + 1)
else:
return_str += str(obj[key])
return return_str
if "params" in req:
param_str = params_to_str(req['params'], 0)
payload_str = req['method'] + str(req['id']) + req['api_key'] + param_str + str(req['nonce'])
req['sig'] = hmac.new(
bytes(str(SECRET_KEY), 'utf-8'),
msg=bytes(payload_str, 'utf-8'),
digestmod=hashlib.sha256
).hexdigest()
```
#### C# Example
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
private const string API_KEY = "YOUR_API_KEY";
private const string API_SECRET = "YOUR_API_SECRET";
private static string GetSign(Dictionary request)
{
var paramsDict = request["params"] as Dictionary;
// Ensure the params are alphabetically sorted by key
// Note: For nested objects or lists, implement recursive sorting similar to JS/Python examples
string paramString = paramsDict != null
? string.Join("", paramsDict.Keys.OrderBy(key => key).Select(key => key + paramsDict[key]))
: "";
string sigPayload = request["method"].ToString()
+ request["id"].ToString()
+ API_KEY
+ paramString
+ request["nonce"].ToString();
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(API_SECRET)))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(sigPayload));
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
```
#### Java Example
```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiRequestJson {
private Long id;
private String method;
private Map params;
private String sig;
@JsonProperty("api_key")
private String apiKey;
private Long nonce;
}
//------------
public class SigningUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final int MAX_LEVEL = 3;
public static boolean verifySignature(ApiRequestJson apiRequestJson, String secret) {
try {
return genSignature(apiRequestJson, secret).equalsIgnoreCase(apiRequestJson.getSig());
} catch (Exception e) {
return false;
}
}
@SuppressWarnings("unchecked")
public static String getParamString(final Object paramObject) {
StringBuilder sb = new StringBuilder();
appendParamString(sb, paramObject, 0);
return sb.toString();
}
@SuppressWarnings("unchecked")
private static void appendParamString(final StringBuilder paramsStringBuilder, final Object paramObject, final int level) {
if (level >= MAX_LEVEL) {
paramsStringBuilder.append(paramObject.toString());
return;
}
if (paramObject instanceof Map) {
TreeMap params = new TreeMap<>((Map) paramObject);
for (Map.Entry entry : params.entrySet()) {
if (entry.getValue() instanceof Double) {
paramsStringBuilder
.append(entry.getKey())
.append((new BigDecimal(entry.getValue().toString()))
.stripTrailingZeros()
.toPlainString());
} else if (entry.getValue() instanceof List || entry.getValue() instanceof Map) {
paramsStringBuilder
.append(entry.getKey());
appendParamString(paramsStringBuilder, entry.getValue(), level + 1);
} else {
paramsStringBuilder
.append(entry.getKey())
.append(entry.getValue());
}
}
} else if (paramObject instanceof List) {
List list = (List) paramObject;
for (Object o : list) {
appendParamString(paramsStringBuilder, o, level + 1);
}
} else {
paramsStringBuilder.append(paramObject.toString());
}
}
public static String genSignature(ApiRequestJson apiRequestJson, String secret)
throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] byteKey = secret.getBytes(StandardCharsets.UTF_8);
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA256);
mac.init(keySpec);
String paramsString = "";
if (apiRequestJson.getParams() != null) {
paramsString += getParamString(apiRequestJson.getParams());
}
String sigPayload =
apiRequestJson.getMethod()
+ apiRequestJson.getId()
+ apiRequestJson.getApiKey()
+ paramsString
+ (apiRequestJson.getNonce() == null ? "" : apiRequestJson.getNonce());
byte[] macData = mac.doFinal(sigPayload.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(macData);
}
public static ApiRequestJson sign(ApiRequestJson apiRequestJson, String secret)
throws InvalidKeyException, NoSuchAlgorithmException {
apiRequestJson.setSig(genSignature(apiRequestJson, secret));
return apiRequestJson;
}
public static void main(String[] argv) throws InvalidKeyException, NoSuchAlgorithmException {
ApiRequestJson apiRequestJson = ApiRequestJson.builder()
.id(11L)
.apiKey("token")
.method("public/auth")
.nonce(1589594102779L)
.build();
System.out.println(genSignature(apiRequestJson, "secretKey"));
System.out.println(sign(apiRequestJson, "secretKey"));
}
}
```
### Response Format
| Name | Type | Description |
|------|------|-------------|
| id | long | Original request identifier (or -1 if omitted in request). |
| method | string | Method invoked. |
| result | object | Result object (present on success). |
| code | int | 0 for success; see Response and Reason Codes |
| message | string | Optional; server or error message. |
| original | string | Optional; original request as escaped string (for error cases). |
### Response and Reason Codes
#### 200 OK
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 200 | 0 | --:Success |
| 200 | 40401 | NOT_FOUND:Not found |
| 200 | 43012 | SELF_TRADE_PREVENTION:Canceled due to Self Trade Prevention |
#### 400 Bad Request
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 400 | 202 | ACCOUNT_IS_SUSPENDED:Account is suspended |
| 400 | 204 | DUPLICATE_CLORDID:Duplicate client order id |
| 400 | 207 | NO_MARK_PRICE:No mark price |
| 400 | 208 | INSTRUMENT_NOT_TRADABLE:Instrument is not tradable |
| 400 | 209 | INVALID_INSTRUMENT:Instrument is invalid |
| 400 | 213 | INVALID_ORDERQTY:Invalid order quantity |
| 400 | 218 | INVALID_ORDTYPE:Invalid order_type |
| 400 | 220 | INVALID_SIDE:Invalid side |
| 400 | 221 | INVALID_TIF:Invalid time_in_force |
| 400 | 222 | STALE_MARK_PRICE:Stale mark price |
| 400 | 223 | NO_CLORDID:No client order id |
| 400 | 224 | REJ_BY_MATCHING_ENGINE:Rejected by matching engine |
| 400 | 225 | EXCEED_MAXIMUM_ENTRY_LEVERAGE:Exceeds maximum entry leverage |
| 400 | 226 | INVALID_LEVERAGE:Invalid leverage |
| 400 | 227 | INVALID_SLIPPAGE:Invalid slippage |
| 400 | 228 | INVALID_FLOOR_PRICE:Invalid floor price |
| 400 | 229 | INVALID_REF_PRICE:Invalid ref price |
| 400 | 230 | INVALID_REF_PRICE_TYPE:Invalid ref price type |
| 400 | 308 | INVALID_PRICE:Invalid price |
| 400 | 314 | EXCEEDS_MAX_ORDER_SIZE:Exceeds max order size |
| 400 | 315 | FAR_AWAY_LIMIT_PRICE:Far away limit price |
| 400 | 318 | EXCEEDS_MAX_ALLOWED_ORDERS:Exceeds max allowed orders |
| 400 | 319 | EXCEEDS_MAX_POSITION_SIZE:Exceeds max position size |
| 400 | 401 | ACCOUNT_DOES_NOT_EXIST:Account does not exist |
| 400 | 408 | MARGIN_UNIT_IS_SUSPENDED:Margin unit is suspended |
| 400 | 30024 | MAX_AMOUNT_VIOLATED:If create-withdrawal call quantity > max_withdrawal_balance in user-balance api |
| 400 | 40001 | BAD_REQUEST:Bad request |
| 400 | 40002 | METHOD_NOT_FOUND:Method not found |
| 400 | 40003 | INVALID_REQUEST:Invalid request |
| 400 | 40004 | MISSING_OR_INVALID_ARGUMENT:Required argument is blank or missing |
| 400 | 40005 | INVALID_DATE:Invalid date |
| 400 | 40006 | DUPLICATE_REQUEST:Duplicate request received |
| 400 | 40102 | INVALID_NONCE:Nonce value differs by more than 60 seconds |
| 400 | 40107 | EXCEED_MAX_SUBSCRIPTIONS:Session subscription limit has been exceeded |
| 400 | 50001 | ERR_INTERNAL:Internal error |
| 400 | 50002 | DW_CREDIT_LINE_NOT_MAINTAINED:If create-withdrawal call breaches credit line check |
#### 401 Unauthorized
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 401 | 40101 | UNAUTHORIZED:Not authenticated, or key/signature incorrect |
| 401 | 40103 | IP_ILLEGAL:IP address not whitelisted |
| 401 | 40104 | USER_TIER_INVALID:Disallowed based on user tier |
#### 408 Request Timeout
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 408 | 40801 | REQUEST_TIMEOUT:Request has timed out |
#### 429 Too Many Requests
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 429 | 42901 | TOO_MANY_REQUESTS:Requests have exceeded rate limits |
#### 500 Internal Server Error
| HTTP Status | Code | Message Code / Description |
|-------------|------|----------------------------|
| 500 | 201 | NO_POSITION:No position |
| 500 | 203 | ACCOUNTS_DO_NOT_MATCH:Accounts do not match |
| 500 | 205 | DUPLICATE_ORDERID:Duplicate order id |
| 500 | 206 | INSTRUMENT_EXPIRED:Instrument has expired |
| 500 | 210 | INVALID_ACCOUNT:Account is invalid |
| 500 | 211 | INVALID_CURRENCY:Currency is invalid |
| 500 | 212 | INVALID_ORDERID:Invalid order id |
| 500 | 214 | INVALID_SETTLE_CURRENCY:Invalid settlement currency |
| 500 | 215 | INVALID_FEE_CURRENCY:Invalid fee currency |
| 500 | 216 | INVALID_POSITION_QTY:Invalid position quantity |
| 500 | 217 | INVALID_OPEN_QTY:Invalid open quantity |
| 500 | 219 | INVALID_EXECINST:Invalid exec_inst |
| 500 | 301 | ACCOUNT_IS_IN_MARGIN_CALL:Account is in margin call |
| 500 | 302 | EXCEEDS_ACCOUNT_RISK_LIMIT:Exceeds account risk limit |
| 500 | 303 | EXCEEDS_POSITION_RISK_LIMIT:Exceeds position risk limit |
| 500 | 304 | ORDER_WILL_LEAD_TO_IMMEDIATE_LIQUIDATION:Order will lead to immediate liquidation |
| 500 | 305 | ORDER_WILL_TRIGGER_MARGIN_CALL:Order will trigger margin call |
| 500 | 306 | INSUFFICIENT_AVAILABLE_BALANCE:Insufficient available balance |
| 500 | 307 | INVALID_ORDSTATUS:Invalid order status |
| 500 | 309 | MARKET_IS_NOT_OPEN:Market is not open |
| 500 | 310 | ORDER_PRICE_BEYOND_LIQUIDATION_PRICE:Order price beyond liquidation price |
| 500 | 311 | POSITION_IS_IN_LIQUIDATION:Position is in liquidation |
| 500 | 312 | ORDER_PRICE_GREATER_THAN_LIMITUPPRICE:Order price is greater than the limit up price |
| 500 | 313 | ORDER_PRICE_LESS_THAN_LIMITDOWNPRICE:Order price is less than the limit down price |
| 500 | 316 | NO_ACTIVE_ORDER:No active order |
| 500 | 317 | POSITION_NO_EXIST:Position does not exist |
| 500 | 320 | EXCEEDS_INITIAL_MARGIN:Exceeds initial margin |
| 500 | 321 | EXCEEDS_MAX_AVAILABLE_BALANCE:Exceeds maximum available balance |
| 500 | 406 | ACCOUNT_IS_NOT_ACTIVE:Account is not active |
| 500 | 407 | MARGIN_UNIT_DOES_NOT_EXIST:Margin unit does not exist |
| 500 | 409 | INVALID_USER:Invalid user |
| 500 | 410 | USER_IS_NOT_ACTIVE:User is not active |
| 500 | 411 | USER_NO_DERIV_ACCESS:User does not have derivative access |
| 500 | 412 | ACCOUNT_NO_DERIV_ACCESS:Account does not have derivative access |
| 500 | 415 | BELOW_MIN_ORDER_SIZE:Below Min. Order Size |
| 500 | 501 | EXCEED_MAXIMUM_EFFECTIVE_LEVERAGE:Exceeds maximum effective leverage |
| 500 | 604 | INVALID_COLLATERAL_PRICE:Invalid collateral price |
| 500 | 605 | INVALID_MARGIN_CALC:Invalid margin calculation |
| 500 | 606 | EXCEED_ALLOWED_SLIPPAGE:Exceed allowed slippage |
| 500 | 613 | INVALID_ISOLATION_ID:Invalid isolation ID |
| 500 | 614 | EXCEEDS_ISOLATED_POSITION_LIMIT:Exceeds maximum allowed number of isolated position |
| 500 | 615 | ACCOUNT_DOES_NOT_SUPPORT_ISOLATED_POSITION:Account does not support isolated position |
| 500 | 616 | CREATE_ISOLATED_POSITION_FAILED:Failed to create isolated position |
| 500 | 617 | DUPLICATED_INSTRUMENT_ORDER_FOR_ISOLATED_MARGIN:Account already have isolated position with same instrument |
| 500 | 618 | TOO_MANY_PENDING_ISOLATED_MARGIN_REQUESTS:Exceeds request limit for isolated margin order |
| 500 | 619 | UNSUPPORTED_OPERATION_ON_ISOLATED_POSITION:Unsupported operation on isolated position |
| 500 | 620 | CREATE_ISOLATED_POSITION_TIMEOUT:Request for create isolated position has timed out |
| 400 | 1110 | REDUCE_ONLY_REJECTED:Rejected REDUCE_ONLY create-order request |
| 500 | 43003 | FILL_OR_KILL:FOK order has not been filled and cancelled |
| 500 | 43004 | IMMEDIATE_OR_CANCEL:IOC order has not been filled and cancelled |
| 500 | 43005 | POST_ONLY_REJ:Rejected POST_ONLY create-order request (normally happened when exec_inst contains POST_ONLY but time_in_force is NOT GOOD_TILL_CANCEL) |
| 500 | 120009 | REJECTED:Request rejected by upstream service |
| 500 | 130008 | NON_APPLICABLE:Operation not applicable for current state |
### 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 |
### 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.
### Common Issues
#### TOO_MANY_REQUESTS After Websocket Connects
Websocket rate limits are pro-rated based on the calendar-second that the websocket connection was opened.
This means, depending on the fraction of the calendar-second that the connection was established, the rate limit could be pro-rated to a small number.
By adding a 1-second sleep after establishing the websocket connection, and before requests are sent, this will ensure the rate limit is properly reset and sync'd to your session.
This will avoid occurrences of rate-limit (TOO_MANY_REQUESTS) errors.
#### INVALID_NONCE On All Requests
The nonce should be the UTC Unix timestamp in milliseconds.
If this has been carefully checked, then the issue occurs when the system clock of the client machine is greater than 60 seconds in the future / past.
Usually, re-syncing with the NTP time server on the client machine will correct the issue.
If the issue persists, you can try deliberately subtracting N seconds from the nonce to force it to be N seconds in the past, which is still within the 60-second past tolerance.
---
## Websocket API
## Welcome
Welcome to the Crypto.com Exchange API v1 reference documentation.
The Crypto.com Exchange API v1 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.
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, as well as sample requests and code snippets in JavaScript, Python which can be viewed on the right.
### Notes on Exchange Upgrade and API Versions
- Exchange v1 API is the latest version of API which can trade Spot / Derivatives / Margin.
- Derivatives v1 API has been upgraded into Exchange v1 API with additional capabilities for Spot Trading / Margin Trading / Wallet Management. As Exchange v1 API is a superset of Derivatives v1 API, existing customer can continue using the same for trading.
- For full details about the exchange upgrade, please refer to this (blog post)[https://crypto.com/product-news/introducing-the-gen-3-0-crypto-com-exchange] with FAQ documents.
---
## API Explorer
export function ApiExplorerCards() {
const { siteConfig } = useDocusaurusContext();
const items = siteConfig.customFields?.apiExplorerItems || [];
const baseUrl = siteConfig.baseUrl.replace(/\/$/, '');
if (!items.length) return No explorers available for this API.;
return (
{items.map((item) => (
))}
);
}
---
## Guides
Browse by topic. Each guide links to API reference for that area.
## FIX Protocol