Quick Start Guide
Welcome to the Kalqix API integration guide. This document will help you authenticate, access market data, manage orders, and monitor your account.
Getting Started
Web App
Get your API key and secret from the Kalqix web app:
1. Navigate to User > Settings > API Keys
2. Click "Create New API Key"
3. Save your api_key and api_secret securely
Testnet Web App: https://testnet.kalqix.com
API Base URL
All API requests should be made to:
https://testnet-api.kalqix.com/v1/
Example endpoints
-
Orders:
https://testnet-api.kalqix.com/v1/orders -
Market Data:
https://testnet-api.kalqix.com/v1/markets
Authentication
Required Headers
Every API request must include these headers:
const headers = {
'x-api-key': 'your-api-key',
'x-api-signature': 'hmac-signature',
'x-api-timestamp': 'timestamp-in-ms',
'Content-Type': 'application/json'
};
Header Descriptions:
- x-api-key (string): Your API key from Settings
- x-api-signature (string): HMAC-SHA256 signature of the request (see below)
- x-api-timestamp (string): Current Unix timestamp in milliseconds
- Content-Type (string): Always "application/json"
HMAC Signature Generation
We use HMAC-SHA256 to authenticate API requests. This allows the server to verify that a request was created by someone who holds your API secret without ever sending the secret over the network.
How It Works
1. Create a canonical string from the request details
2. Sign it with your API secret using HMAC-SHA256
3. Send the signature in the x-api-signature header
Canonicalization Helper
For consistency, use this helper function to canonicalize JSON payloads:
function canonicalizePayload(payload) {
return JSON.stringify(payload, Object.keys(payload).sort());
}
Implementation
const crypto = require('crypto');
function signRequest(method, path, body, timestamp, apiSecret) {
let payload = '';
if (body && Object.keys(body).length > 0) {
payload = canonicalizePayload(body);
}
const canonical = `${method}|${path}|${payload}|${timestamp}`;
return crypto.createHmac('sha256', apiSecret)
.update(canonical)
.digest('hex');
}
// example usage
const method = 'POST';
const path = '/v1/orders';
const body = {
ticker: 'BTC_USDC',
price: '100000',
quantity: '0.1',
side: 'BUY',
order_type: 'LIMIT',
timestamp: Date.now()
};
const timestamp = Date.now();
const signature = signRequest(method, path, body, timestamp, apiSecret);
Important Notes:
-
The timestamp must match the one sent in the
x-api-timestampheader -
The path must include the
/v1/prefix -
Request body is canonicalized with sorted keys for consistency
-
For requests without a body, the payload will be an empty string
-
Signatures expire after 5 minutes to prevent replay attacks
Ethereum Message Signature for Orders
For Order Placement
For order placement, you also need to sign a message with your Ethereum wallet. This signature proves ownership of the wallet account.
Important: This signature goes in the request body, not the headers (unlike the HMAC signature).
Message Signing Requirements
All signed messages must:
-
Include an explicit
actionfield (e.g.,PLACE_ORDER,CANCEL_ORDER,TRANSFER,WITHDRAW) -
Include a
timestampfield as integer milliseconds (useDate.now()) -
Use canonicalized JSON with sorted keys for consistency
-
Be within 5 minutes of server time (replay protection)
Implementation
const { ethers } = require('ethers');
async function signOrderMessage(order, walletSeed) {
// 1. Create wallet from seed phrase
const wallet = ethers.Wallet.fromPhrase(walletSeed);
// 2. Build the signed payload with action and timestamp
const payload = {
action: 'PLACE_ORDER',
ticker: order.ticker,
price: order.price,
quantity: order.quantity,
side: order.side,
order_type: order.order_type,
timestamp: Date.now()
};
// 3. Canonicalize and sign
const signingString = canonicalizePayload(payload);
const signature = await wallet.signMessage(signingString);
const walletAddress = wallet.address;
return {
signature,
walletAddress,
timestamp: payload.timestamp
};
}
// Example usage
const order = {
ticker: 'BTC_USDC',
price: '100000',
quantity: '0.1',
side: 'BUY',
order_type: 'LIMIT'
};
// Your wallet seed phrase (12, 15, 18, 21, or 24 words)
const walletSeed = 'your twelve word seed phrase here for wallet creation';
const { signature, walletAddress, timestamp }
= await signOrderMessage(order, walletSeed);
Important Notes:
-
Timestamps must be integers in milliseconds (use
Date.now()) -
Messages expire after 5 minutes for security
-
Use
canonicalizePayload()to ensure consistent key ordering -
The
actionfield is required for all signed operations -
The signed payload includes
action, but the API request body does not
Alternative Wallet Creation Methods
You can create wallets using different methods depending on your security setup:
// From private key
const privateKey = '0x...'; // Your private key
const wallet = new ethers.Wallet(privateKey);
// From mnemonic (same as seed phrase)
const mnemonic = 'your twelve word mnemonic here';
const wallet = ethers.Wallet.fromPhrase(mnemonic);
// Generate a new random wallet
const randomWallet = ethers.Wallet.createRandom();
console.log('New wallet address:', randomWallet.address);
Security Best Practices:
-
Never hardcode private keys or seed phrases in your code
-
Use environment variables for sensitive credentials
-
Consider using a hardware wallet for production systems
-
For trading bots, use dedicated API-only wallets with limited funds
Complete Order Placement Example
This example demonstrates the complete flow of placing an order, combining both HMAC authentication and wallet signature.
/**
* Complete Example: Programmatically place an order on Kalqix
*
* This script:
* - Signs an order using your wallet (mnemonic or private key)
* - Signs the HTTP request using your API secret (HMAC)
* - Sends a POST /v1/orders request to the Kalqix API
*
* Required environment variables:
* - API_KEY
* - API_SECRET
* - WALLET_SEED (mnemonic phrase) OR
* - WALLET_PRIVATE_KEY
*/
require('dotenv').config();
const crypto = require('crypto');
const { ethers } = require('ethers');
/**
* Configuration from environment
*/
const API_KEY = process.env.API_KEY;
const API_SECRET = process.env.API_SECRET;
// Set either WALLET_SEED or WALLET_PRIVATE_KEY
const WALLET_SEED = process.env.WALLET_SEED;
const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY;
/**
* Canonicalize JSON payload (sorted keys)
*/
function canonicalizePayload(payload) {
return JSON.stringify(payload, Object.keys(payload).sort());
}
/**
* Create an HMAC signature for a Kalqix API request.
*/
function signRequest(method, path, body, timestamp, apiSecret) {
let payload = '';
if (body && Object.keys(body).length > 0) {
payload = canonicalizePayload(body);
}
const canonical = `${method}|${path}|${payload}|${timestamp}`;
return crypto.createHmac('sha256', apiSecret).update(canonical).digest('hex');
}
/**
* Place an order with wallet and HMAC signatures
*/
async function placeOrder(orderData) {
let wallet;
if (WALLET_SEED) {
wallet = ethers.Wallet.fromPhrase(WALLET_SEED);
} else if (WALLET_PRIVATE_KEY) {
wallet = new ethers.Wallet(WALLET_PRIVATE_KEY);
} else {
throw new Error('Please provide WALLET_SEED or WALLET_PRIVATE_KEY in environment variables.');
}
const timestamp = Date.now();
// 1. Build the payload (without action)
const payload = {
ticker: orderData.ticker,
side: orderData.side,
order_type: orderData.order_type,
quantity: orderData.quantity,
quote_quantity: orderData.quote_quantity || '',
price: orderData.price || '',
time_in_force: orderData.time_in_force || 0,
expires_at: orderData.expires_at || 0,
timestamp
};
// 2. Sign with wallet (payload + action)
const signingString = canonicalizePayload({ action: 'PLACE_ORDER', ...payload });
const walletSignature = await wallet.signMessage(signingString);
// 3. Request body = payload + signature (no action field)
const requestBody = {
...payload,
signature: walletSignature
};
// 4. Generate HMAC signature for headers
const method = 'POST';
const path = '/v1/orders';
const hmacSignature = signRequest(method, path, requestBody, timestamp, API_SECRET);
// 5. Send request
const response = await fetch('https://testnet-api.kalqix.com/v1/orders', {
method: 'POST',
headers: {
'x-api-key': API_KEY,
'x-api-signature': hmacSignature, // HMAC for API auth
'x-api-timestamp': timestamp.toString(),
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody) // Contains Ethereum signature
});
return await response.json();
}
// Example usage
(async () => {
const result = await placeOrder({
ticker: 'BTC_USDC',
price: '100000',
quantity: '0.1',
side: 'BUY',
order_type: 'LIMIT'
});
console.log('Order result:', result);
})().catch(console.error);
Running the Example
-
Install dependencies:
npm install dotenv ethers -
Create a
.envfile:API_KEY=your_api_key_here API_SECRET=your_api_secret_here WALLET_SEED=your twelve word seed phrase here # OR WALLET_PRIVATE_KEY=0x... -
Run the script:
node place_order.js
Important Notes
Timestamp Requirements
-
Timestamps must be integers in milliseconds (not ISO strings)
-
Requests rejected if timestamp is in the future or older than 5 minutes (replay protection)
-
Use
Date.now()in JavaScript orint(time.time() * 1000)in Python -
All signed message payloads must include timestamp field