Institutional Trading Gateway API Specification
Version: 1.1.7
Last Updated: September 2026
Release Notes: Enhanced FIX protocol integration and added support for dynamically loading FIX session configurations.
Table of Contents
- Introduction & Architecture Overview
- Getting Started & Integration Prerequisites
- Security & Authentication
- 3.1 REST API Authentication
- 3.2 WebSocket Authentication
- Session Management
- REST API Reference
- 5.1 Push Instruments & FIX Sessions (MANDATORY PREREQUISITE)
- 5.2 Retrieve Configured Instruments
- 5.3 Place Order
- 5.4 Edit Order / Order Cancel Replace
- 5.5 Cancel Order
- 5.6 Get Order Status
- WebSocket Real-Time API
- 6.1 Connection & Authentication
- 6.1.1 WebSocket Connection and Order Events
- 6.2 Channel Subscription
- 6.3 Real-Time Order Execution Reports
- 6.3.1 Order Execution Reports
- 6.3.2 Order Cancel Rejected Report
- 6.3.3 Session Configuration Status
- 6.4 Real-Time Market Data Quotes
- 6.5 Ping / Pong Heartbeat Protocol
- Event Replay & Gap Recovery Protocol
- Error Codes & Diagnostics
- SDK Examples
- 9.1 Comprehensive Node.js Client Example
- 9.2 Trading API Gateway - Client Integration Guide
- 9.3 Authentication Overview
- 9.4 Request Signature Generation
- 9.5 Timestamp and Nonce Requirements
- 9.6 Payload Encryption
- 9.7 AES Encryption Example
- 9.8 AES Decryption Example
- 9.9 REST API Request Flow
- 9.10 Example: Place Order Request
- 9.11 Example: Get Instrument Information
- 9.12 Response Handling
- 9.13 WebSocket Connection
- 9.14 WebSocket Authentication
- 9.15 WebSocket Signature Generation
- 9.16 WebSocket Authentication Responses
- 9.17 WebSocket Message Encryption
- 9.18 WebSocket Heartbeat Mechanism
- 9.19 Client Requirement
- 9.20 WebSocket Reconnection
- 9.21 WebSocket Recovery Flow
- 9.22 Client Responsibilities
- security
1. Introduction & Architecture Overview
Welcome to the Enterprise Trading Bridge API. This document serves as the definitive, long-term guide for integrating with our high-performance trading infrastructure. The system is designed for institutional-grade trading integrations with encrypted communication, authenticated API access, real-time event streaming, and event recovery mechanisms.
The platform provides two primary interfaces:
- REST API (/v1): Used for synchronous operations, dynamic FIX session management, instrument configuration, order routing (Limit, Market, Replace, Cancel), and querying order status.
- WebSocket API (/ws): Used for real-time market data quote streaming and continuous order execution report broadcasts.
2. Getting Started & Integration Prerequisites
Follow these steps in order when integrating with the gateway:
- Obtain API Credentials: Acquire your
API Key,API Secret(for HMAC-SHA256 signature generation), and sharedAES Key+AES IV(32-byte key, 16-byte IV for payload encryption). - Whitelist IP Address: Ensure client server IP addresses are whitelisted at the gateway firewall level.
- Establish REST / WS Connections:
- Base REST URL:
http://<HOST>:<PORT>/v1(e.g.,http://192.168.1.145:3120/v1) - WebSocket URL:
ws://<HOST>:<PORT>/ws(e.g.,ws://192.168.1.145:3120/ws) - [MANDATORY] Push Instrument & Session Mappings: Call
POST /v1/instrumentsbefore executing any trades. The bridge uses this data to validate price tick sizes, step sizes, and route orders to the correct FIX sessions.
CRITICAL: Orders referencing a symbol not configured via
POST /v1/instrumentswill be rejected with error code13001(SYMBOL_NOT_CONFIGURED).
3. Security & Authentication
The gateway enforces strict end-to-end security via HMAC-SHA256 request signing, 5-second window timestamp checking, nonce replay caching, and AES-256-CBC payload encryption.
3.1 REST API Authentication
All protected REST requests must include the following HTTP headers:
| Header Name | Type | Description |
|---|---|---|
x-api-key |
string |
Public API Key issued to your account. |
x-timestamp |
string |
Current 13-digit Unix millisecond timestamp. |
x-nonce |
string |
Unique random string (minimum 16 hexadecimal characters). |
x-signature |
string |
HMAC-SHA256 signature calculated over the request components. |
Signature Generation Formula
signature = HMAC_SHA256(API_SECRET, API_KEY + TIMESTAMP + NONCE + HTTP_METHOD + REQUEST_PATH + REQUEST_BODY)
Rules:
- HTTP_METHOD must be uppercase (e.g., POST, GET, PUT, DELETE).
- REQUEST_PATH includes the full path (e.g., /v1/orders).
- REQUEST_BODY is the exact wire payload string (e.g., {"encryptedData":"..."}). For GET or DELETE requests without a body, use "" (empty string).
Request Payload Envelope Format (AES-256-CBC)
All JSON request bodies must be encrypted using AES-256-CBC with PKCS7 padding and sent in a base64 envelope:
{
"encryptedData": "U2FsdGVkX19zomeEncryptedBase64StringRepresetingOrder..."
}
Server responses are returned using the same encrypted envelope format.
3.2 WebSocket Authentication
WebSocket authentication requires sending an auth message immediately after TCP connection:
{
"type": "auth",
"apiKey": "<YOUR_API_KEY>",
"encryptedData": "<Base64 Encrypted JSON Auth Payload>"
}
Authentication Payload (Before AES Encryption)
{
"timestamp": "1787032498541",
"nonce": "8f7a2c9d4e1b3f0a9c8d7e6f5a4b3c2d",
"signature": "<HMAC_SHA256(API_SECRET, API_KEY + timestamp + nonce)>",
"lastSequence": 0,
"clientVersion": "1.1.0",
"platform": "linux"
}
Server Response
{
"type": "auth.success"
}
auth.success– Authentication successful.auth.failure– Authentication failed. Check your credentials, timestamp, nonce, or signature.
4. Session Management
- REST Interface: Stateless. Every request is independently validated and authenticated.
- WebSocket Interface: Stateful. Heartbeat (Ping/Pong) frames are monitored. If no Pong is received for some period of time (e.g, 30 sec), the socket will be forcefully disconnected.
5. REST API Reference
| REST Endpoint | HTTP Method | Description |
|---|---|---|
/v1/instruments |
POST |
Mandatory setup: push symbols, FIX sessions, trade rules, LP routing. |
/v1/instruments |
GET |
Retrieve configured instrument mappings. |
/v1/orders/place_order |
POST |
Place a new order (Market, Limit). |
/v1/orders/order_cancel_replace |
POST |
Edit or replace an active order (price/qty). |
/v1/orders/cancel_order |
POST |
Cancel a resting order. |
/v1/orders/order_status |
POST |
Query active order status and execution state. |
5.1 Push Instruments & FIX Sessions (MANDATORY PREREQUISITE)
- Endpoint:
POST /v1/instruments - Auth Required: Yes
This endpoint registers dynamic FIX sessions, symbol trading constraints, and LP routing configuration into the gateway engine.
Field Reference — fixSessions Object
| Field | Type | Required | Description |
|---|---|---|---|
sessionId |
string |
✅ | Unique identifier for the FIX session (e.g., lp-binance). |
type |
enum |
✅ | Which refer following session is for trading / market data purpose trading for trade quote for market data. |
version |
string |
✅ | FIX protocol version used by the session (e.g., FIX.4.4). |
connectionRole |
enum |
✅ | FIX connection role. Values: initiator or acceptor. |
accountId |
string |
✅ | Liquidity provider account identifier. |
host |
string |
✅ | FIX gateway host/IP address. |
port |
integer |
✅ | FIX gateway connection port. |
senderCompId |
string |
✅ | FIX SenderCompID value used for session identification. |
targetCompId |
string |
✅ | FIX TargetCompID value used for session identification. |
username |
string |
✅ | FIX session username for authentication. |
password |
string |
✅ | FIX session password for authentication. |
ssl |
string |
❌ | Indicates whether the FIX gateway supports or requires SSL/TLS. The default value depends on the session type and is true for trading sessions. |
use_ssl |
string |
❌ | Specifies whether the FIX client should use SSL/TLS when connecting to the configured FIX gateway. The default value depends on the session type and is true for trading sessions. |
reset_on_logon |
string |
❌ | Specifies whether the FIX session sequence numbers should be reset when the client logs on to the FIX session. The default value depends on the session type; for trading sessions, the default is false |
sessionSchedule |
object |
✅ | Defines when the FIX session is active. |
Field Reference — sessionSchedule Sub-Object
| Field | Type | Required | Description |
|---|---|---|---|
timezone |
string |
✅ | Timezone used for session schedule (e.g., UTC). |
startDay |
string |
✅ | Session start day (e.g., Sunday). |
endDay |
string |
✅ | Session end day (e.g., Friday). |
startTime |
string |
✅ | Session start time in HH:mm:ss format. |
endTime |
string |
✅ | Session end time in HH:mm:ss format. |
Field Reference — liquidityProviders Object
| Field | Type | Required | Description |
|---|---|---|---|
lpId |
string |
✅ | Unique identifier for the liquidity provider (e.g., BINANCE, LMAX). |
name |
string |
✅ | Human-readable liquidity provider name (e.g., Binance Institutional). |
sessionId |
string |
✅ | Reference to the associated FIX session from fixSessions. |
Field Reference — symbols Object
| Field | Type | Required | Description |
|---|---|---|---|
symbol |
string |
✅ | Broker-side trading symbol identifier (e.g., BTC_USD). |
description |
string |
✅ | Human-readable instrument description (e.g., Bitcoin CFD). |
baseCurrency |
string |
✅ | Base currency/asset code (e.g., BTC, ETH). |
quoteCurrency |
string |
✅ | Quote currency/settlement currency code (e.g., USD). |
tradeRules |
object |
✅ | Trading constraints and precision rules. |
execution |
object |
✅ | Supported order execution types. |
routing |
object |
✅ | Liquidity provider routing configuration. |
Field Reference — tradeRules Sub-Object
| Field | Type | Required | Description |
|---|---|---|---|
pricePrecision |
integer |
✅ | Number of decimal places supported for prices. |
quantityPrecision |
integer |
✅ | Number of decimal places supported for quantities. |
tickSize |
number |
✅ | Minimum price movement increment (e.g., 0.01). |
stepSize |
number |
✅ | Minimum quantity increment (e.g., 0.00001). |
contractSize |
number |
✅ | The number of units of the underlying asset represented by one lot (e.g., contractSize = 100000` (EUR/USD)). |
minOrderQty |
number |
✅ | Minimum allowed order quantity. |
maxOrderQty |
number |
✅ | Maximum allowed order quantity. |
Field Reference — execution Sub-Object
| Field | Type | Required | Description |
|---|---|---|---|
allowMarket |
boolean |
✅ | Indicates whether market orders are supported. |
allowLimit |
boolean |
✅ | Indicates whether limit orders are supported. |
allowStop |
boolean |
✅ | Indicates whether stop orders are supported. |
allowStopLimit |
boolean |
✅ | Indicates whether stop-limit orders are supported. |
Field Reference — routing Sub-Object
| Field | Type | Required | Description |
|---|---|---|---|
tradeLpId |
string |
✅ | Liquidity provider identifier used for order routing. Must match an entry in liquidityProviders. |
marketDataLpId |
string |
✅ | Liquidity provider identifier used for market data. Must match an entry in liquidityProviders. |
Logical Request Example (AES Encrypted)
{
"fixSessions": [
{
"sessionId": "lp-trading",
"type": "trading",
"version": "FIX.4.4",
"connectionRole": "initiator",
"accountId": "CLIENT_TEM",
"host": "45.77.136.252",
"port": 10011,
"senderCompId": "TD_MCAP_FIX",
"targetCompId": "CENTROID_SOL",
"username": "MCAP_FIX",
"password": "3PUjVGDY",
"ssl": true,
"use_ssl": true,
"reset_on_logon": true,
"sessionSchedule": {
"timezone": "UTC",
"startDay": "Sunday",
"endDay": "Sunday",
"startTime": "00:00:05",
"endTime": "00:00:00"
}
},
{
"sessionId": "lp-marketdata",
"type": "quote",
"version": "FIX.4.4",
"connectionRole": "initiator",
"accountId": "CLIENT_TEM",
"host": "45.77.136.252",
"port": 10010,
"senderCompId": "MD_MCAP_FIX",
"targetCompId": "CENTROID_SOL",
"username": "MCAP_FIX",
"password": "3PUjVGDY",
"ssl": false,
"use_ssl": false,
"reset_on_logon": true,
"sessionSchedule": {
"timezone": "UTC",
"startDay": "Sunday",
"endDay": "Sunday",
"startTime": "00:00:05",
"endTime": "00:00:00"
}
}
],
"liquidityProviders": [
{
"lpId": "CENTROID_TRADE",
"name": "Centroid Trade Execution LP",
"sessionId": "lp-trading"
},
{
"lpId": "CENTROID_MD",
"name": "Centroid Market Data LP",
"sessionId": "lp-marketdata"
}
],
"symbols": [
{
"symbol": "XAUUSD",
"description": "Gold Spot / US Dollar",
"baseCurrency": "XAU",
"quoteCurrency": "USD",
"tradeRules": {
"pricePrecision": 2,
"quantityPrecision": 2,
"tickSize": 0.01,
"stepSize": 0.01,
"contractSize": 100,
"minOrderQty": 0.01,
"maxOrderQty": 100
},
"execution": {
"allowMarket": true,
"allowLimit": true,
"allowStop": true,
"allowStopLimit": true
},
"routing": {
"tradeLpId": "CENTROID_TRADE",
"marketDataLpId": "CENTROID_MD"
}
},
{
"symbol": "XAGUSD",
"description": "Silver Spot / US Dollar",
"baseCurrency": "XAG",
"quoteCurrency": "USD",
"tradeRules": {
"pricePrecision": 3,
"quantityPrecision": 2,
"tickSize": 0.001,
"stepSize": 0.01,
"contractSize": 5000,
"minOrderQty": 0.01,
"maxOrderQty": 500
},
"execution": {
"allowMarket": true,
"allowLimit": true,
"allowStop": true,
"allowStopLimit": true
},
"routing": {
"tradeLpId": "CENTROID_TRADE",
"marketDataLpId": "CENTROID_MD"
}
},
{
"symbol": "XPTUSD",
"description": "Platinum Spot / US Dollar",
"baseCurrency": "XPT",
"quoteCurrency": "USD",
"tradeRules": {
"pricePrecision": 2,
"quantityPrecision": 2,
"tickSize": 0.01,
"stepSize": 0.01,
"contractSize": 100,
"minOrderQty": 0.01,
"maxOrderQty": 100
},
"execution": {
"allowMarket": true,
"allowLimit": true,
"allowStop": true,
"allowStopLimit": true
},
"routing": {
"tradeLpId": "CENTROID_TRADE",
"marketDataLpId": "CENTROID_MD"
}
}
]
}
⚠️ FIX Sessions — Required Configuration
Important: The bridge requires exactly two FIX sessions.
{
"fixSessions":[
{
.
.
"type":"trading"
.
.
.
.
},
{
.
.
"type":"quote"
.
.
.
.
}
]
}
Trading Session (type = "trading")
Used for the trade session connection.
Quote Session (type = "quote")
Used for the market data session connection.
✅ Required Setup
fixSessions
├── trading → Trade Session Connection
└── quote → Market Data Session Connection
5.2 Retrieve Configured Instruments
- Endpoint:
GET /v1/instruments - Auth Required: Yes
Returns all instruments and FIX sessions configured for the account.
5.3 Place Order
- Endpoint:
POST /v1/orders/place_order - Auth Required: Yes
Submits a new order to the FIX gateway engine.
Field Reference — Order Request
| Field Name | Type | Required | Description |
|---|---|---|---|
symbol |
string |
✅ | Configured broker symbol (e.g., XAUUSD). |
side |
string |
✅ | Order side: buy or sell. |
type |
string |
✅ | Order type: market, limit. |
quantity |
string |
✅ | Quantity requested (e.g., "0.01"). Must comply with stepSize, minOrderQty and maxOrderQty. |
price |
string |
⚠️ | Limit price (e.g., "2400.00"). Required for limit orders. |
clientOrderId |
string |
✅ | Client-generated unique identifier for tracking the order. Minimum length: 1 Maximum length: 31 characters. |
timeInForce |
string |
❌ | Order execution duration. Allowed values: gtc, ioc, fok. Default: gtc. |
clordlinkid |
string |
❌ | Client reference triplet: AccountID-TicketID-GroupName (e.g., 1000-12345-DemoGrp1). |
direction |
string |
❌ | Position intent: in (Open / Entry) or out (Close / Exit). |
idempotencyKey |
string |
✅ | Unique key used to prevent duplicate order submissions. Minimum length: 16 Maximum length: 64 characters. |
Logical Request Example
{
"symbol": "XAUUSD",
"side": "buy",
"type": "market",
"quantity": "0.01",
"price": "3333.14",
"direction": "in",
"clientOrderId": "ORDTSTNOS1",
"clordlinkid": "1000-12345-DemoGrp1",
"idempotencyKey": "idemp-xau-001",
"timeInForce": "gtc",
}
Decrypted Success Response (201 Created)
{
"success": true,
"data": {
"clientOrderId": "ORDTSTNOSR1",
"status": "new order single request received",
"correlationId": "req-12345"
}
}
5.4 Edit Order / Order Cancel Replace
- Endpoint:
POST /v1/orders/order_cancel_replace - Auth Required: Yes
Field Reference — Replace Order
| Field Name | Type | Required | Description |
|---|---|---|---|
clientOrderId |
string |
✅ | Client-generated unique identifier for tracking the order. Minimum length: 1 Maximum length: 31 characters. |
originalClientOrderId |
string |
✅ | The clientOrderId of the existing order that you want to replace. Use the same clientOrderId that was provided when the original order was placed. |
symbol |
string |
✅ | Trading symbol (e.g., XAUUSD). |
side |
string |
✅ | Order side: buy or sell This field cannot be modified. |
type |
string |
✅ | Order type: limit This field cannot be modified. |
quantity |
string |
❌ | Updated total order quantity (e.g., "0.02"). |
price |
string |
❌ | Updated limit price (e.g., "2405.00"). |
timeInForce |
string |
❌ | Order execution duration. Allowed values: gtc, ioc, fok. This field cannot be modified. |
idempotencyKey |
string |
✅ | Unique key used to prevent duplicate order submissions. Minimum length: 16 Maximum length: 64 characters. |
Request Example
{
"symbol": "XAUUSD",
"side": "buy",
"type": "market",
"quantity": "0.11",
"price": "2000.05",
"clientOrderId": "ORDOCRTOT1",
"originalClientOrderId": "OGORDCLID3",
"timeInForce": "fok",
"idempotencyKey": "idemp-xau-002"
}
Decrypted Success Response (201 Created)
{
"success": true,
"data": {
"clientOrderId": "ORDOCRTOT1",
"originalClientOrderId": "OGORDCLID3",
"status": "order cancel replace request received",
"correlationId": "req-12345"
}
}
Order Cancel/Replace Lifecycle
The Order Cancel/Replace operation allows you to modify an existing order.
The operation generates two execution reports:
- The original order is cancelled.
- The replacement order is accepted.
Important
When sending a Cancel/Replace request, use the existing order's clientOrderId as originalClientOrderId.
The Cancel/Replace request must also contain a new clientOrderId for the replacement order.
Example
Assume the original order was placed with:
clientOrderId: NEWORDSGL11
The order placement response from websocket:
{
"type": "order.update",
"data": {
"CentroidOrderId": "12715023",
"ExecutionID": "12715023",
"averageFillPrice": "0.000000",
"clientOrderId": "NEWORDSGL11",
"lastFillPrice": "0.000000",
"lastFillQuantity": "0.000000",
"orderType": "limit",
"price": "3333.140000",
"quantity": "0.010000",
"remainingQuantity": "0.010000",
"side": "buy",
"status": "new",
"symbol": "XAUUSD",
"text": "New Request",
"timeInForce": "gtc",
"timestamp": 1787581196036,
"totalFilledQuantity": "0.000000",
"type": "order.accepted",
"sequence": 263
}
}
This is the original order.
1. Send Cancel/Replace Request
When you want to modify this order, use:
originalClientOrderId = NEWORDSGL11
clientOrderId = CANREPORD11
Here:
originalClientOrderId= theclientOrderIdof the existing order you want to modify.clientOrderId= a new ID that identifies the replacement order.
2. Original Order Cancelled
After the Cancel/Replace request is processed, you will receive an order.cancelled event for the original order:
{
"type": "order.update",
"data": {
"CentroidOrderId": "12715023",
"ExecutionID": "12715023",
"averageFillPrice": "0.000000",
"clientOrderId": "NEWORDSGL11",
"lastFillPrice": "0.000000",
"lastFillQuantity": "0.000000",
"orderType": "limit",
"price": "3333.140000",
"quantity": "0.010000",
"remainingQuantity": "0.010000",
"side": "buy",
"status": "cancelled",
"symbol": "XAUUSD",
"text": "Cancelled",
"timeInForce": "gtc",
"timestamp": 1787581279110,
"totalFilledQuantity": "0.000000",
"type": "order.cancelled",
"sequence": 264
}
}
This confirms that the original order has been cancelled.
3. Replacement Order Accepted
You will then receive an order.accepted event for the new order:
{
"type": "order.update",
"data": {
"CentroidOrderId": "12715024",
"ExecutionID": "12715024",
"averageFillPrice": "0.000000",
"clientOrderId": "CANREPORD11",
"lastFillPrice": "0.000000",
"lastFillQuantity": "0.000000",
"orderType": "limit",
"originalClientOrderId": "NEWORDSGL11",
"price": "1000.050000",
"quantity": "0.100000",
"remainingQuantity": "0.100000",
"side": "buy",
"status": "new",
"symbol": "XAUUSD",
"text": "New Request",
"timeInForce": "gtc",
"timestamp": 1787581279111,
"totalFilledQuantity": "0.000000",
"type": "order.accepted",
"sequence": 265
}
}
This confirms that the replacement order was successfully created.
The new active order is now:
clientOrderId: CANREPORD11
CentroidOrderId: 12715024
Which clientOrderId Should You Use?
After the replacement order is accepted, use the new clientOrderId for future operations on the order.
Before Cancel/Replace:
NEWORDSGL11
After Successful Cancel/Replace:
CANREPORD11
The relationship between the orders is:
Original Order
clientOrderId: NEWORDSGL11
|
| Cancel/Replace
v
Replacement Order
clientOrderId: CANREPORD11
originalClientOrderId: NEWORDSGL11
If the Cancel/Replace Fails
If the replacement order is rejected, the new clientOrderId is not an active order.
In that case, continue using the original clientOrderId as the order reference.
Cancel/Replace Failed
|
v
Continue using:
NEWORDSGL11
Summary
| Stage | Event | Client Order ID |
|---|---|---|
| Original order placed | order.accepted |
NEWORDSGL11 |
| Original order cancelled | order.cancelled |
NEWORDSGL11 |
| Replacement accepted | order.accepted |
CANREPORD11 |
Integration rule: Use the original order's clientOrderId as originalClientOrderId when sending a Cancel/Replace request. After receiving order.accepted for the replacement order, use the new clientOrderId for subsequent operations. If the replacement is rejected, continue using the original clientOrderId.
5.5 Cancel Order
- Endpoint:
POST /v1/orders/cancel_order - Auth Required: Yes
Field Reference — Cancel Order
| Field Name | Type | Required | Description |
|---|---|---|---|
clientOrderId |
string |
✅ | A unique ID generated by the client to identify the order. Use a new and unique value for each order request. Minimum length: 1 characters. Maximum length: 31 characters. |
originalClientOrderId |
string |
✅ | The clientOrderId of the existing order that you want to cancel. Use the same clientOrderId that was provided when the original order was placed. |
symbol |
string |
✅ | The trading instrument for the order, for example XAUUSD. |
side |
string |
✅ | Order side of the order buy or sell. |
idempotencyKey |
string |
✅ | A unique key generated by the client to ensure that the same request is not processed more than once if it is submitted multiple times. Minimum length: 16 characters. Maximum length: 64 characters. |
Request Example
{
"symbol": "XAUUSD",
"side": "buy",
"clientOrderId": "ORDCANCLEE2",
"originalClientOrderId": "OGORDTK2",
"idempotencyKey": "idemp-xau-003",
}
Decrypted Success Response (201 Created)
{
"success": true,
"data": {
"clientOrderId": "ORDCANCLEE2",
"originalClientOrderId": "OGORDTK2",
"status": "order cancel replace request received",
"correlationId": "req-12345"
}
}
5.6 Get Order Status
- Endpoint:
POST /v1/orders/order_status - Auth Required: Yes
Queries the execution state and fill statistics for a specific order.
Field Reference — Cancel Order
| Field Name | Type | Required | Description |
|---|---|---|---|
CentroidOrderId |
string |
✅ | The unique order ID assigned by Centroid. This value is returned when the order is created. Use the CentroidOrderId of the order whose status you want to retrieve. |
originalClientOrderId |
string |
✅ | The clientOrderId of the order whose current status you want to retrieve. Use the same clientOrderId that was provided when the order was originally submitted. |
symbol |
string |
✅ | The trading instrument associated with the order, for example XAUUSD. |
side |
string |
✅ | The side of the order. Use buy for a buy order or sell for a sell order. |
idempotencyKey |
string |
✅ | A unique key generated by the client to prevent the same request from being processed more than once. Minimum length: 16 characters. Maximum length: 64 characters. |
Request Example
{
"CentroidOrderId": "12714448",
"originalClientOrderId": "ORGCLIID2",
"symbol": "XAUUSD",
"side": "buy",
"idempotencyKey": "idemp-xau-004"
}
Decrypted Response Example
{
"success": true,
"data": {
"CentroidOrderId": "12714448",
"originalClientOrderId": "ORGCLIID2",
"status": "order status request received",
"correlationId": "req-12345"
}
}
⚠️ Note
Some FIX Business Message Reject responses may not be forwarded to the WebSocket client. As a result, you may occasionally receive no response for a request.
This can happen, for example, when: - An invalid
originalOrderIdis provided in a Get Order Status request. - An Edit Order or Order Cancel Replace request is sent without making any changes to the order.Please ensure that you provide a valid
originalOrderIdand make at least one valid modification when submitting an Edit Order request.
6. WebSocket Real-Time API
6.1 Connection & Authentication
Connect to ws://<HOST>:<PORT>/ws and send the HMAC authenticated auth message as detailed in Section 3.2.
6.1.1 WebSocket Connection and Order Events
Before performing any trading-related operations, make sure your WebSocket connection is established and ready to receive messages.
Important
The REST API response only confirms that your request was received or acknowledged. It does not necessarily represent the final result of the order operation.
All order-related events, including order acceptance, execution, cancellation, rejection, and status updates, are delivered through the WebSocket connection.
Therefore, clients should establish the WebSocket connection before sending any trading-related requests.
Request and Response Flow
The general flow is:
1. Establish WebSocket connection
|
v
2. Send trading request through REST
|
v
3. REST response
Request received/acknowledged
|
v
4. Wait for WebSocket event
|
v
5. Process the actual order result
REST Response
The REST response confirms that the request was received and accepted for processing.
For example:
{
"success": true,
"data": {
"clientOrderId": "ODweIe3sKz45",
"originalClientOrderId": "ODweIe3sKz43",
"status": "order cancel replace request received"
}
}
This response does not mean that the order operation has completed successfully.
WebSocket Response
The actual order status and lifecycle events are delivered through WebSocket.
For example:
{
"type": "order.update",
"data": {
"clientOrderId": "ODweIeIe3sKz45",
"status": "new",
"type": "order.accepted"
.
.
.
.
.
}
}
The WebSocket event is the source of the actual order state.
Business Validation Errors
Some business-level validation errors may be returned directly in the REST response.
For example, if a request fails validation because of an invalid order quantity, price, symbol, or other business rule, the REST API may return an error immediately.
Therefore, clients should handle both:
- REST responses — request acknowledgement and immediate business validation errors.
- WebSocket events — order lifecycle events and final order status.
Recommended Integration
Clients should follow this sequence:
Connect to WebSocket
|
v
Confirm WebSocket is ready
|
v
Send REST trading request
|
+----------------------+
| |
v v
REST response WebSocket event
| |
| v
| Actual order status
|
v
Handle acknowledgement
or immediate validation error
Important: Always establish the WebSocket connection before submitting orders or other trading-related requests. This ensures that the client is ready to receive the corresponding order events as soon as they are generated.
6.2 Channel Subscription
Clients submit an encrypted JSON subscription payload to subscribe to market data quote feeds:
{
"type": "subscribe",
"apiKey": "<YOUR_API_KEY>",
"encryptedData": "<Base64 Encrypted JSON Payload>"
}
encryptedData Payload (Before AES Encryption)
{
"channels": ["market_data.XAUUSD"]
}
Encrypted responce from server
{
"type":"encrypted_event",
"encryptedData":"uoIHKQ5nEwfFXYnVbmKdCkZNSPIvsaquyg/PW0UqyiZjUlE3a9vPr+msExrL8MfYvPKKrAV/6d9VtGP5PN7KRw=="
}
Decrypted Response
{
"type": "subscribe.ack",
"channels": [
"market_data.EURUSD"
]
}
6.3 Real-Time Order Execution Reports
6.3.1 Order Execution Reports
Execution events are pushed in real time whenever an order status changes (new, partially_filled, filled, cancelled, rejected):
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
CentroidOrderId |
string |
✅ | The unique order ID assigned to the order by Centroid. | "12714788" |
ExecutionID |
string |
✅ | The unique ID assigned to this specific execution report or event. | "12714788" |
averageFillPrice |
string |
✅ | The average price at which the order has been filled so far. | "1000.000000" |
clientOrderId |
string |
✅ | The client-generated identifier for the order. | "CANCELEEORD2" |
lastFillPrice |
string |
✅ | The execution price of the most recent fill event. | "1000.050000" |
lastFillQuantity |
string |
✅ | The quantity executed in the most recent fill event. | "0.100000" |
orderType |
string |
✅ | The type of order (e.g., market, limit, stop). |
"limit" |
originalClientOrderId |
string |
❌ | The client order ID of the original order prior to a cancel/replace operation. | "ODweIesjzs86" |
price |
string |
✅ | The order price specified at submission (limit or stop price). | "1000.050000" |
quantity |
string |
✅ | The original total order quantity submitted by the client. | "0.100000" |
remainingQuantity |
string |
✅ | The portion of the order quantity that remains open and unfilled. | "0.000000" |
side |
string |
✅ | The side of the order, either buy or sell. |
"buy" |
status |
string |
✅ | The current lifecycle status of the order (e.g., new, partially_filled, filled, cancelled, rejected). |
"cancelled" |
symbol |
string |
✅ | The financial instrument or trading symbol associated with the order. | "XAUUSD" |
text |
string |
❌ | Additional descriptive text, status messages, or reason details associated with the event. | "Execution" |
timeInForce |
string |
✅ | Specifies how long the order remains active (e.g., gtc, ioc, fok). |
"gtc" |
timestamp |
number |
✅ | The timestamp indicating when the event occurred, in Unix milliseconds. | 1787572272335 |
totalFilledQuantity |
string |
✅ | The cumulative quantity filled for the order across all execution events. | "0.100000" |
type |
string |
✅ | Identifies the event type (e.g., order.new or order.accepted, order.partially_filled, order.filled, order.cancelled, order.rejected). |
"order.cancelled" |
sequence |
number |
✅ | The sequential number assigned to this event for ordering and tracking purposes. | 257 |
Encrypted responce from server
{
"type":"encrypted_event",
"encryptedData":"uoIHKQ5nEwfFXYnVbmKdCkZNSPIvsaquyg/PW0UqyiZjUlE3a9vPr+msExrL8MfYvPKKrAV/6d9VtGP5PN7KRw=="
}
Decrypted response
{
"type": "order.update",
"data": {
"CentroidOrderId": "12714449",
"ExecutionID": "12714449",
"averageFillPrice": "4645.090000",
"clientOrderId": "ODweIe3sKz37",
"lastFillPrice": "4645.090000",
"lastFillQuantity": "0.100000",
"orderType": "limit",
"price": "6000.050000",
"quantity": "0.100000",
"remainingQuantity": "0.000000",
"side": "buy",
"status": "filled",
"symbol": "XAUUSD",
"text": null,
"timeInForce": "gtc",
"timestamp": 1787563403708,
"totalFilledQuantity": "0.100000",
"type": "order.filled",
"sequence": 233
}
}
6.3.2 Order Cancel Rejected Report
If Centroid is unable to process an Order Cancel Request, a order.cancel_rejected event is sent through the WebSocket.
This event indicates that the cancellation request was rejected and the order was not successfully cancelled.
Example
{
"CentroidOrderId": "N/A",
"clientOrderId": "SUM",
"originalClientOrderId": "ODR",
"rejectReason": "cannot cancel",
"status": "rejected",
"timestamp": 1787580215980,
"type": "order.cancel_rejected",
"sequence": 260
}
Response Fields
| Field | Description |
|---|---|
CentroidOrderId |
The Centroid order ID associated with the request. This may be "N/A" when the cancellation request is rejected before an order ID can be associated with it. |
clientOrderId |
The client-generated ID associated with the cancel request. |
originalClientOrderId |
The clientOrderId of the order that the client attempted to cancel. |
rejectReason |
The reason why Centroid rejected the cancellation request. |
status |
Indicates the result of the request. For a rejected cancellation, this value is rejected. |
timestamp |
The time at which the rejection event was generated, represented as a Unix timestamp in milliseconds. |
type |
Identifies the event type. For a rejected cancel request, this value is order.cancel_rejected. |
sequence |
The sequential number assigned to the event. |
Important
A order.cancel_rejected event means that the cancel request was not successful.
The order should therefore not be treated as cancelled based on this event.
The rejectReason field provides the reason for the rejection. In the example above:
rejectReason: "cannot cancel"
means that Centroid was unable to cancel the requested order.
Clients should use the originalClientOrderId to identify the order for which the cancellation was requested and handle the order according to its current state.
6.3.3 Session Configuration Status
After a FIX connection configuration is submitted, the system sends a session.configuration event through the WebSocket to report the current status of the configured sessions.
This event allows the client to determine whether the Market Data and Trading sessions are currently active.
Example
{
"type": "session.configuration",
"data": {
"marketDataSessionActive": false,
"timestamp": 1787586081277,
"tradingSessionActive": false
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
marketDataSessionActive |
boolean |
Indicates whether the configured Market Data FIX session is currently active. true means the session is connected and active. false means the Market Data session is not currently active. |
tradingSessionActive |
boolean |
Indicates whether the configured Trading FIX session is currently active. true means the session is connected and active. false means the Trading session is not currently active. |
timestamp |
number |
The time at which the session status was reported, represented as a Unix timestamp in milliseconds. |
type |
string |
Identifies the event as a session configuration status event. This value is session.configuration. |
Understanding the Session Status
The values of marketDataSessionActive and tradingSessionActive represent the current connection status of each configured FIX session.
Both Sessions Active
{
"marketDataSessionActive": true,
"tradingSessionActive": true
}
This indicates that both the Market Data and Trading FIX sessions are currently connected and active.
Trading Session Inactive
{
"marketDataSessionActive": true,
"tradingSessionActive": false
}
The Market Data session is active, but the Trading session is currently inactive.
Trading requests should not be submitted until the Trading session becomes active.
Market Data Session Inactive
{
"marketDataSessionActive": false,
"tradingSessionActive": true
}
The Trading session is active, but the Market Data session is currently inactive.
Both Sessions Inactive
{
"marketDataSessionActive": false,
"tradingSessionActive": false
}
Neither session is currently active.
This can occur when the FIX sessions are not connected or the connection/configuration is not valid.
Important
A value of false only indicates that the corresponding FIX session is not currently active. It does not by itself identify the reason.
If a session remains inactive, verify the FIX connection configuration, including:
- FIX host and port
- SenderCompID
- TargetCompID
- Username and password
- SSL settings
- Session schedule
- Other required FIX session parameters
Once the configuration is valid and the FIX session successfully connects, the corresponding field will report:
{
"marketDataSessionActive": true,
"tradingSessionActive": true
}
6.4 Real-Time Market Data Quotes
Real-time Best Bid / Ask (BBO) market data quotes pushed over WebSocket:
Before Decryption
{"type":"encrypted_event",
"encryptedData":"9rJeKLuTdvePOXYYXD/gj0DuIbVDL6nR9TU9Zi6oJsYrjGgaUALebc4QjCxAQOxRNmonxTkvlRQmbJO/NFFQu6HMREUEmfTpRDpr9CtBWw3G4eIor0+eeZhA4OLdnoX9NlS2SLBFfhbsnvFQWWRuNL7pBhAG/anflZqmQpY/4tSWdcoqjm3Ud5KJ3BZ316kd5ejrR6pxeEsMYuPqoPNWj6DZp5dbt/0QK/Kk2WI4l1joqPapDYx0VcadvcCVplmkuzIVUAO08qkzfSbH5cv5q5aQc+sfvVAcrbTycvABs6w="}
After Decryption
{
"type": "market.data",
"channel": "market_data.XAUUSD",
"data": {
"symbol": "XAUUSD",
"bids": [{ "price": "2399.50", "size": "100.0" }],
"asks": [{ "price": "2400.50", "size": "100.0" }],
"timestamp": 1787032498575
}
}
6.5 Ping / Pong Heartbeat Protocol
The Trading Gateway uses the standard WebSocket Ping/Pong mechanism to monitor connection health.
- The server periodically sends Ping frames.
- Clients must respond with Pong frames.
- Most WebSocket client libraries handle Ping/Pong automatically. If your client library does not support this, your application must send a Pong frame in response to every Ping received.
- If the server does not receive a Pong response within the expected interval, the connection will be closed.
7. Event Replay & Gap Recovery Protocol
To prevent lost events during brief network disconnections, the gateway maintains a monotonically increasing sequence ledger using a persistent event stream.
- Submit
lastSequenceinteger in your WebSocketauthpayload (e.g.,"lastSequence": 149). - If
lastSequence < serverCurrentSequence, the server immediately streams missing execution reports: - Event:
replay.start - Event:
replay.event(Array of missed execution reports) - Event:
replay.end(hasMore: false,gapDetected: false) - If
gapDetected: true(sequence purged), the client should callPOST /v1/orders/order_statusvia REST to reconcile state.
The Event Replay mechanism is used to recover events that may have been missed during a temporary WebSocket disconnection.
The client must keep track of the last event sequence number it successfully received and processed. This sequence number should be sent in the WebSocket auth payload as lastSequence.
How Event Replay Works
When the client reconnects, the server checks the lastSequence provided by the client against the events currently available in the server's event stream.
The server maintains the most recent 100 events for replay processing. Therefore, a maximum of 100 recent events can be considered during a single replay operation.
For example, if the server currently has events up to sequence 300:
Available event sequence:
1 ... 200 201 202 203 ... 298 299 300
└───────────────┘
Latest 100
If lastSequence is 255, the server returns events from sequence 256 to 300. If lastSequence is 50, the server can only return the latest 100 available events, which are sequences 201 to 300.
Encrypted response
{
"type": "encrypted_event",
"encryptedData": "V9y3E5PDv65bEEcoWd3RWaRLkOIWY83sRrUrKYKxWDY="
}
After decrypted the response
Reply event start
{
"type": "replay.start"
}
Actual missing events
{
"type": "replay.event",
"event": {
"CentroidOrderId": "12715217",
"ExecutionID": "12715217",
"averageFillPrice": "0.000000",
"clientOrderId": "NEWORDSGL15",
"lastFillPrice": "0.000000",
"lastFillQuantity": "0.000000",
"orderType": "limit",
"price": "3333.140000",
"quantity": "0.010000",
"remainingQuantity": "0.010000",
"side": "buy",
"status": "cancelled",
"symbol": "XAUUSD",
"text": "Cancelled",
"timeInForce": "gtc",
"timestamp": 1787641211017,
"totalFilledQuantity": "0.000000",
"type": "order.cancelled",
"sequence": 289
}
}
Reply event end
{
"type": "replay.end",
"hasMore": false,
"gapDetected": false
}
8. Error Codes & Diagnostics
Centralized error code classifications:
| Category | Code Range | Description |
|---|---|---|
| Authentication | 11000 - 11011 |
Invalid API key, invalid HMAC signature, expired timestamp, or nonce reuse. |
| Authorization | 11012 - 11018 |
Permission and access control failures. |
| Validation | 12000 - 12001 |
Invalid request payload or format errors. |
| Business Logic | 13000 - 13008 |
Trading and account operation failures. |
| Rate Limiting | 14000 |
Request frequency violations. |
| WebSocket | 16000 - 16002 |
WebSocket connection and message errors. |
| System Failure | 17000 |
Internal server or ZMQ engine timeout. |
Error Response Envelope
{
"success": false,
"error": {
"code": "13001",
"message": "Symbol XAUUSD has not been configured. Push instrument configuration via POST /v1/instruments first.",
"timestamp": "2026-08-18T11:05:00.000Z",
"correlationId": "req-1787032497"
}
}
9. SDK Examples
9.1 Comprehensive Node.js Client Example
The following snippet demonstrates how to properly encrypt/decrypt payloads, generate HMAC signatures, place a REST order, and authenticate a WebSocket connection to stream encrypted market data.
9.2 Trading API Gateway - Client Integration Guide
9.2.1 Overview
This document explains how to integrate with the Trading API Gateway.
The gateway supports:
- REST API authentication using HMAC-SHA256 signatures
- AES-256-CBC payload encryption
- AES-256-CBC response decryption
- WebSocket authentication
- WebSocket heartbeat monitoring
- WebSocket reconnect and recovery flow
9.3 Authentication Overview
All REST API requests require authentication headers.
Required headers:
| Header | Description |
|---|---|
x-api-key |
Client API key |
x-timestamp |
Current timestamp in milliseconds |
x-nonce |
Unique random value generated for each request |
x-signature |
HMAC-SHA256 request signature |
Example:
x-api-key: <API_KEY>
x-timestamp: 1720000000000
x-nonce: 8f7a2c9d4e1b...
x-signature: 9d8f7a6c...
9.4 Request Signature Generation
The gateway validates every request using an HMAC-SHA256 signature.
The signature input format is:
API_KEY + TIMESTAMP + NONCE + HTTP_METHOD + REQUEST_PATH + REQUEST_BODY
All values are concatenated without separators.
Example:
tex_test_key1720000000000abc123POST/v1/orders{"encryptedData":"xxxxx"}
The signature is generated:
const signature = crypto
.createHmac(
"sha256",
API_SECRET
)
.update(signatureBase, "utf8")
.digest("hex");
9.5 Timestamp and Nonce Requirements
9.5.1 Timestamp
The timestamp must be the current Unix timestamp in milliseconds.
Example:
1720000000000
The server uses this to prevent replay attacks.
9.5.2 Nonce
The nonce must be unique for every request.
Recommended:
- Generate using cryptographically secure random bytes.
- Never reuse the same nonce.
Example:
const nonce =
crypto.randomBytes(16)
.toString("hex");
9.6 Payload Encryption
All REST request bodies must be encrypted before sending.
The encryption algorithm:
AES-256-CBC
Encrypted payload format:
{
"encryptedData":"BASE64_ENCRYPTED_VALUE"
}
Example:
Original payload:
{
"symbol":"BTC_USD",
"side":"buy",
"quantity":"10"
}
Sent payload:
{
"encryptedData":"g83hd82jd92..."
}
9.7 AES Encryption Example
Example implementation:
function encryptData(text) {
const cipher =
crypto.createCipheriv(
"aes-256-cbc",
AES_KEY,
AES_IV
);
let encrypted =
cipher.update(
text,
"utf8",
"base64"
);
encrypted += cipher.final("base64");
return encrypted;
}
9.8 AES Decryption Example
Example implementation:
function decryptData(encryptedText) {
const decipher =
crypto.createDecipheriv(
"aes-256-cbc",
AES_KEY,
AES_IV
);
let decrypted =
decipher.update(
encryptedText,
"base64",
"utf8"
);
decrypted += decipher.final("utf8");
return decrypted;
}
The same AES key and IV are used to decrypt responses.
9.9 REST API Request Flow
The request flow is:
Client
|
| 1. Create JSON payload
|
| 2. Encrypt payload
|
| 3. Create signature
|
| 4. Add authentication headers
|
| 5. Send HTTP request
|
Gateway
|
| 6. Validate signature
|
| 7. Decrypt payload
|
| 8. Process request
|
| 9. Encrypt response
|
Client
9.10 Example: Place Order Request
Endpoint:
POST /v1/orders/place_order
Request payload:
{
"symbol": "XAUUSD",
"side": "buy",
"type": "market",
"quantity": "0.01",
"price": "3333.14",
"direction": "in",
"clientOrderId": "ORDTSTNOS1",
"clordlinkid": "1000-12345-DemoGrp1",
"idempotencyKey": "idemp-xau-001",
"timeInForce": "gtc",
}
The payload must be encrypted before sending.
9.11 Example: Get Instrument Information
Endpoint:
GET /v1/instruments
GET requests do not contain a body.
Signature input:
API_KEY + TIMESTAMP + NONCE + GET + /v1/instruments + ""
Example:
tex_test_key1720000000000abc123GET/v1/instruments
9.12 Response Handling
Encrypted responses are returned as:
{
"encryptedData":"BASE64_VALUE"
}
The client must decrypt the value using:
AES-256-CBC
After decryption, the original JSON response is returned.
Example:
Encrypted:
{
"encryptedData":"83hd82jd..."
}
After decryption:
{
"success":true,
"data":{
"orderId":"ORD123"
}
}
9.13 WebSocket Connection
WebSocket endpoint:
ws://<gateway-host>/ws
Example:
ws://127.0.0.1:3120/ws
9.14 WebSocket Authentication
Authentication must be the first message after establishing the WebSocket connection.
Connection flow:
Client Gateway
CONNECT ---------------->
AUTH ---------------->
<--------------- auth.success
Authentication payload (refer to the example payload provided above in this documentation (3.2)).
9.15 WebSocket Signature Generation
WebSocket authentication signature uses:
API_KEY + TIMESTAMP + NONCE
Example:
const signatureBase =
API_KEY +
timestamp +
nonce;
const signature =
crypto
.createHmac(
"sha256",
API_SECRET
)
.update(signatureBase)
.digest("hex");
9.16 WebSocket Authentication Responses
Successful authentication:
{
"type":"auth.success"
}
Failed authentication:
{
"type":"auth.failure",
"message":"Authentication failed"
}
9.17 WebSocket Message Encryption
{
"encryptedData":"BASE64_VALUE"
}
The client should decrypt the payload using the configured AES key and IV.
9.18 WebSocket Heartbeat Mechanism
The gateway uses the standard WebSocket Ping/Pong protocol.
Heartbeat flow:
Gateway Client
Ping frame ------------->
<------------- Pong frame
Ping/Pong frames are WebSocket protocol control frames.
They are not application JSON messages.
Most WebSocket libraries automatically respond with Pong.
9.19 Client Requirement
The client WebSocket library must support RFC6455 Ping/Pong.
If the library does not automatically respond, the client must manually send Pong when receiving a Ping event.
Example:
socket.on(
"ping",
() => {
socket.pong();
}
);
9.20 WebSocket Reconnection
Clients should implement automatic reconnect handling.
Recommended strategy:
First retry : 100ms
Second retry : 200ms
Third retry : 400ms
Fourth retry : 800ms
The delay should increase exponentially to avoid reconnect storms.
9.21 WebSocket Recovery Flow
When reconnecting:
- Create a new WebSocket connection.
- Authenticate again.
- Provide the last successfully processed sequence number.
Example:
{
"type":"auth",
"lastSequence":12345
}
The server uses this value to replay missed events.
Recovery flow:
Client reconnects
|
Authenticate with lastSequence
|
Server sends:
replay.event
replay.event
replay.event
|
replay.end
|
Client resumes live event processing
9.22 Client Responsibilities
The client application must:
- Generate a new nonce for every request.
- Generate the correct HMAC signature.
- Encrypt REST request payloads.
- Decrypt encrypted responses.
- Authenticate immediately after WebSocket connection.
- Support WebSocket Ping/Pong.
- Automatically reconnect after connection loss.
- Clients should use exponential backoff for automatic reconnects to prevent reconnect storms.
- Re-authenticate after reconnect.
- Restore subscriptions after reconnect.
- Store the last processed sequence number for event recovery.
- Provide a valid
originalOrderIdwhen requesting order status. - When submitting an Edit Order request, ensure that at least one valid order field is modified.
10. Security
The infrastructure enforces stringent security protocols:
- Authentication: Key-pair requirement for all programmatic access.
- Encryption: AES-256-CBC for all request and response payloads.
- Signature (HMAC): Validates integrity of
path,method, andbody. - Timestamp & Nonce: Prevents replay attacks. Requests older than the tolerance window (default 5000ms) are rejected.
- Replay Prevention: Nonce cache ensures the exact same request cannot be processed twice.
- TLS: All connections enforce TLS 1.2+ minimum.
- IP Whitelist: Enforced at the gateway level.
- Rate Limiting: Centralized sliding-window rate limiting is enforced to control request frequency and prevent excessive or abusive traffic.
- Best Practices: Rotate keys regularly, use isolated IP whitelists, and log all
clientOrderIds locally.