Authorization
This secion provides details on how to authorize your API requests using custom headers. The authorization relies on three headers: X-SIGNATURE, X-TIMESTAMP, and X-CLIENT-ID. Follow the steps below to securely access the API.
HTTP headers
To authenticate a request, include the following headers in your API request:
Header | Description |
---|---|
X-SIGNATURE | A signature generated using HMAC-SHA256. |
X-TIMESTAMP | The request timestamp in RFC3339 format. |
X-CLIENT-ID | Client ID generated when register in Xellar TSS API Service Dashboard. |
How to Generate the Signature
The signature is generated using the following formula:
stringToSign = ${method}:${url}:${minifiedJSON}:${timestamp}
signature = HMAC-SHA256(stringToSign, clientSecret)
Components of stringToSign
:
- method: The HTTP method (e.g., POST, GET, etc.). Uppercase
- url: API Endpoint URL Path
- minifiedJSON: Request payload in minified JSON format. Hash with sha-256, then make it lowercase. lower(sha256(minify(JSONRequestBody)))
- timestamp: The current timestamp in
RFC3339
format (e.g.,2024-11-19T12:34:56Z
). This value must be same asX-TIMESTAMP
header.
Example stringToSign
Method : GET
URL : /api/v1/wallet/check/544f7d79
Request Body : -
Timestamp : 2024-11-20T10:48:02+07:00
Client Secret : your-client-secret-from-the-dashboard
-----------------------------------------
minifiedJSON : lower(sha256(""))
String To Sign : GET:/api/v1/wallet/check/544f7d79:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855:2024-11-20T10:48:02+07:00
Signature : VKPH47xJppCxQSG5fLQ0yPoCesFxyH05Jg7YLLgB0Gc=
Method : POST
URL : /api/v1/wallet/account
Request Body : { "subId": "8b6aae63-cb8d-495d-9102-cc46b052aba1"}
Timestamp : 2024-11-20T10:49:12+07:00
Client Secret : your-client-secret-from-the-dashboard
-----------------------------------------
minifiedJSON : lower(sha256("{\"subId\":\"8b6aae63-cb8d-495d-9102-cc46b052aba1\"}"))
String To Sign : POST:/api/v1/wallet/account:18c58628ca72ad1900e4ba4f18c2daf64b88d930d978714d385dbdbe5e496319:2024-11-20T10:49:12+07:00
Signature : a6Nc4MvfpQsmDytOATTP1gKlpe8ww7HtrSr9+gJPYfM=
Example Implementation
const crypto = require('crypto');
/**
* Minifies a JSON string by removing unnecessary spaces.
*/
function minifiedJSON(inputJSON) {
if (!inputJSON) {
return "";
}
try {
const parsed = JSON.parse(inputJSON);
return JSON.stringify(parsed); // Minified JSON
} catch (error) {
throw new Error(`Invalid JSON input: ${error.message}`);
}
}
/**
* Hashes the minified JSON using SHA256 and converts it to lowercase.
*/
function hashMinifiedJSON(inputJSON) {
const minified = minifiedJSON(inputJSON);
const hash = crypto.createHash('sha256').update(minified).digest('hex');
return hash.toLowerCase();
}
/**
* Generates the HMAC signature using the provided inputs.
*/
function generateSignature(method, url, clientSecret, hashedMinifiedJSON, timestamp) {
const stringToSign = `${method.toUpperCase()}:${url}:${hashedMinifiedJSON}:${timestamp}`;
const hmac = crypto.createHmac('sha256', clientSecret).update(stringToSign).digest();
return hmac.toString('base64');
}
/**
* Prepares headers for an authorized request.
*/
function prepareHeaders(method, url, clientId, clientSecret, requestBody) {
const timestamp = new Date().toISOString(); // RFC3339 format
// Hash the minified JSON
const hashedMinifiedJSON = hashMinifiedJSON(requestBody);
// Generate signature
const signature = generateSignature(method, url, clientSecret, hashedMinifiedJSON, timestamp);
// Prepare headers
return {
'Content-Type': 'application/json',
'X-TIMESTAMP': timestamp,
'X-CLIENT-ID': clientId,
'X-SIGNATURE': signature,
};
}
// Example usage
const method = "POST";
const url = "/api/v1/wallet/account";
const clientId = "your-client-id-from-the-dashboard";
const clientSecret = "your-client-secret-from-the-dashboard";
const requestBody = '{"subId": "8b6aae63-cb8d-495d-9102-cc46b052aba1"}';
try {
const headers = prepareHeaders(method, url, clientId, clientSecret, requestBody);
console.log(headers);
} catch (error) {
console.error(`Error: ${error.message}`);
}