HMAC Authentication
Private API endpoints require authentication using HMAC SHA256 signatures generated with your API Secret.
The authentication ensures:
- Request integrity
- Request authenticity
- Protection against replay attacks
Authentication Flow
Every authenticated request follows this process:
- Generate a timestamp
- Build the payload string
- Generate HMAC SHA256 signature
- Base64 encode the signature
- Send request with required headers
- Server validates signature
Required Headers
All private endpoints require these headers:
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your cabinet generated API key |
X-Signature | Yes | Base64 encoded HMAC SHA256 signature |
X-Timestamp | Yes | Request timestamp in milliseconds |
X-Recv-Window | No | Maximum allowed request age in ms |
Interactive API Explorer
In the Send API Request form, enter only your API key and API secret.
The documentation generates X-Timestamp and X-Signature immediately before
the request is sent. It uses the exact method, path, query string, receive
window, and request body shown in the form. Credentials are not saved in the
browser storage.
Step 1 — Generate Timestamp
Timestamp must be UNIX time in milliseconds.
Example:
1770990729000
Example (Javascript):
const timestamp = Date.now().toString()
Step 2 — Build Payload
Payload format:
HTTP_METHOD + "\n" +
PATH + "\n" +
TIMESTAMP + "\n" +
RECV_WINDOW + "\n" +
BODY
Important rules:
- Method must be uppercase
- Path must include query parameters
- New lines must be preserved
- Body must match request exactly
- Empty body must be empty string
Payload Examples
GET example
Request:
GET /open_api/api_profiles?exchanges=BINANCE,KRAKEN
Payload:
GET
/open_api/api_profiles?exchanges=BINANCE,KRAKEN
1770990729000
60000
GET requests have empty body.
POST example
Request:
POST /open_api/position
Body:
{
"key":"value",
"key1":"value1"
}
Payload:
POST
/open_api/position
1770990729000
60000
{"key":"value","key1":"value1"}
Body must match serialized JSON exactly.
Step 3 — Generate Signature
Signature formula:
Base64(HMAC_SHA256(Secret, Payload))
Step 4 — Add Headers
Example headers:
X-API-Key: your_api_key
X-Signature: generated_signature
X-Timestamp: 1770990729000
X-Recv-Window: 60000
Implementation Examples
- Postman
- JavaScript
- Python
// Pre-request Script
const apiKey = "your_api_key";
const apiSecret = "your_secret_key";
const timestamp = Date.now().toString();
const recvWindow = 60000;
const method = pm.request.method;
let path = "/" + pm.request.url.path.join("/");
if (pm.request.url.query.count() > 0) {
path += "?" + pm.request.url.query.map((q) => { return `${q.key}=${q.value}` }).join("&");
}
let body = "";
if (pm.request.body && pm.request.body.raw) {
body = pm.request.body.raw;
}
const payload =
method + "\n" +
path + "\n" +
timestamp + "\n" +
(recvWindow ?? '') + "\n" +
body;
const signature = CryptoJS.enc.Base64.stringify(
CryptoJS.HmacSHA256(payload, apiSecret)
);
pm.request.headers.upsert({
key: "X-API-Key",
value: apiKey
});
pm.request.headers.upsert({
key: "X-Timestamp",
value: timestamp
});
pm.request.headers.upsert({
key: "X-Signature",
value: signature
});
if (recvWindow) {
pm.request.headers.upsert({
key: "X-Recv-Window",
value: recvWindow
});
}
const crypto = require("crypto")
const method = "GET"
const path = "/open_api/api_profiles?exchanges=BINANCE,KRAKEN"
const timestamp = Date.now().toString()
const recvWindow = "60000"
const body = ""
const payload = [
method,
path,
timestamp,
recvWindow,
body
].join("\n")
const signature = crypto
.createHmac("sha256", API_SECRET)
.update(payload)
.digest("base64")
console.log(signature)
import hmac
import hashlib
import base64
import time
method = "GET"
path = "/open_api/api_profiles?exchanges=BINANCE,KRAKEN"
timestamp = str(int(time.time() * 1000))
recv_window = "60000"
body = ""
payload = "\n".join([
method,
path,
timestamp,
recv_window,
body
])
signature = base64.b64encode(
hmac.new(
API_SECRET.encode(),
payload.encode(),
hashlib.sha256
).digest()
).decode()
print(signature)
Server Validation Process
Server validates:
- API key exists and not expired
- Signature matches
- Timestamp is valid
- Request is within receive window
- Payload integrity
Validation logic example:
abs(server_time - timestamp) <= recv_window
If X-Recv-Window is not provided:
Default window:
10000 ms
Security Requirements
Never share your API Secret.
Never send API Secret in requests.
Always generate signature server-side.
Rotate keys if compromised.
Common Mistakes
Most authentication failures are caused by:
| Problem | Cause |
|---|---|
| Invalid signature | Wrong payload formatting |
| Invalid signature | Missing newline characters |
| Invalid signature | Body mismatch |
| Timestamp error | Client clock incorrect |
| Expired request | Receive window too small |
| Invalid signature | Method not uppercase |
Best Practices
Recommended practices:
- Sync time using NTP
- Use 30–60 second receive window
- Always stringify JSON consistently
- Log payload during debugging
- Never modify body after signing
Summary
Authentication requires:
Signature = Base64(HMAC_SHA256(secret, payload))
Payload:
method + path + timestamp + recv_window + body
Headers:
X-API-Key
X-Signature
X-Timestamp
X-Recv-Window