Authentication
Sign every request with HMAC-SHA256 — headers, message format, and reference implementations.
Every request to the gateway is authenticated by an HMAC-SHA256 signature over the exact request. The secret itself is never transmitted.
Required headers
| Header | Value |
|---|---|
x-bot-api-key | your API key |
x-bot-timestamp | current Unix time in milliseconds, as a string |
x-bot-signature | hex HMAC-SHA256 signature (below) |
idempotency-key | required on order placement and cancel — a UUID you generate per trade |
content-type | application/json on requests with a body |
The signature
message = timestamp + METHOD + path + rawBody
signature = hex( HMAC-SHA256( secretKey, message ) )
- No separators between the four parts.
METHODuppercase (POST,GET).pathis the URL path only, no query string — e.g./bot/v1/spot/orders.rawBodyis the exact byte string you transmit. Empty string for bodyless requests (GET, cancel).
The golden rule: sign the bytes you sendBuild the body as a string, sign that string, transmit that same string. Do not let an HTTP library re-serialize the body after signing — key reordering, added whitespace, or changed line endings will invalidate the signature. Interior formatting is fine as long as what you sign is what you send.
30-second replay windowThe request is rejected with
401ifx-bot-timestampis more than 30 seconds from server time. Keep your bot server's clock NTP-synced. The test endpoint returnsserverTimeso you can measure your skew.
Reference implementations
const crypto = require('crypto');
function signedHeaders(method, path, body /* string, '' if none */) {
const timestamp = Date.now().toString();
const message = timestamp + method.toUpperCase() + path + body;
const signature = crypto
.createHmac('sha256', process.env.WELLAT_BOT_SECRET_KEY)
.update(message)
.digest('hex');
return {
'x-bot-api-key': process.env.WELLAT_BOT_API_KEY,
'x-bot-timestamp': timestamp,
'x-bot-signature': signature,
...(body ? { 'content-type': 'application/json' } : {}),
};
}import hashlib, hmac, os, time
def signed_headers(method: str, path: str, body: str = "") -> dict:
timestamp = str(int(time.time() * 1000))
message = f"{timestamp}{method.upper()}{path}{body}"
signature = hmac.new(
os.environ["WELLAT_BOT_SECRET_KEY"].encode(),
message.encode(),
hashlib.sha256,
).hexdigest()
headers = {
"x-bot-api-key": os.environ["WELLAT_BOT_API_KEY"],
"x-bot-timestamp": timestamp,
"x-bot-signature": signature,
}
if body:
headers["content-type"] = "application/json"
return headersNext: Testing Your Integration — verify your signing before you trade.
Updated 28 days ago