Authentication and API Keys
The market and exchange catalog is public: GET /v1/markets, GET /v1/markets/{instrument}, and GET /v1/venues work without credentials. Other REST operations require an API key and an HMAC-SHA256 signature. Keep signing code in a trusted server process.
Key Permissions
Section titled “Key Permissions”A key grants access to specific accounts and scopes. Give a market-data collector market:read, a reconciliation process read permissions, and an execution process the trading permissions it needs.
| Scope | Access |
|---|---|
market:read |
Server time, order books, tickers, trades, and funding rates |
accounts:read |
Accounts, balances, positions, fees, limits, and margin settings |
accounts:write |
Change leverage and margin mode |
orders:read |
Orders, child orders, and fills |
orders:write |
Create, amend, cancel, batch, and dead-man-switch operations |
custody:read |
Linked custodians, allocations, and settlements |
custody:write |
Allocate eligible custody collateral |
transfers:read |
Deposits and internal transfer history |
transfers:write |
Transfer available funds between authorized subaccounts |
keys:read |
Inspect key metadata and account grants |
Provision keys through your approved account’s access process. Record the secret when issued, store it in a secret manager, and restrict the key to your servers’ outbound IP addresses. Use key metadata to check permissions and expiry. Contact Us for access changes.
Required Headers
Section titled “Required Headers”| Header | Value |
|---|---|
X-Trade8-API-Key |
Public key ID |
X-Trade8-Timestamp |
UTC Unix time in whole seconds |
X-Trade8-Signature |
Base64-encoded HMAC-SHA256 signature |
Content-Type |
application/json when sending a JSON body |
Idempotency-Key |
Required for POST, PUT, PATCH, and DELETE |
The timestamp must be within 30 seconds of server time. Synchronize your host with NTP and check GET /v1/time when diagnosing clock errors. Every key is checked against its account grants, scopes, status, expiry, and IP allowlist.
Signing Format
Section titled “Signing Format”Join these five strings with a single newline (\n), in this order:
- Timestamp exactly as sent in the header.
- Uppercase HTTP method.
- Encoded request path and query, including
/v1/and the leading/. - Idempotency key, or an empty string for GET.
- Exact UTF-8 body, or an empty string when the request has no body.
Decode the base64 API secret into its 32 bytes. Compute HMAC-SHA256 over the joined string, then base64-encode the digest. Use standard base64 with padding.
For a GET request, the string ends with two newline bytes:
1788177600\nGET\n/v1/account/balances?account_id=acct_example_main\n\nSerialize JSON once, sign that string, and send those same bytes. Preserve query order and percent encoding. Omit the hostname from the signed path. A change to the body, query, method, timestamp, or idempotency key requires a new signature.
Node.js
Section titled “Node.js”import { createHmac } from 'node:crypto';
const body = JSON.stringify(order);const timestamp = Math.floor(Date.now() / 1000).toString();const path = '/v1/orders';const idempotencyKey = 'order-request-0001';const payload = [timestamp, 'POST', path, idempotencyKey, body].join('\n');const signature = createHmac( 'sha256', Buffer.from(process.env.TRADE8_API_SECRET, 'base64')).update(payload, 'utf8').digest('base64');Download the Node.js Request Helper. It signs the serialized body, enforces the Trade8 origin, rejects redirects, and applies a 10-second request timeout. It leaves retry decisions to the caller.
Python
Section titled “Python”import base64import hashlibimport hmacimport jsonimport osimport time
body = json.dumps(order, separators=(",", ":"), ensure_ascii=False)timestamp = str(int(time.time()))path = "/v1/orders"idempotency_key = "order-request-0001"payload = "\n".join([timestamp, "POST", path, idempotency_key, body])signature = base64.b64encode(hmac.new( base64.b64decode(os.environ["TRADE8_API_SECRET"]), payload.encode("utf-8"), hashlib.sha256).digest()).decode()Download the Python Request Helper.
Signed cURL Request
Section titled “Signed cURL Request”Use the Node helper to calculate headers for this exact read-only request, then pass them to cURL. Keep shell tracing disabled and run this on a trusted host; command-line arguments can be visible to other local users.
# Supply TRADE8_API_KEY and TRADE8_API_SECRET from your secret manager.request_path='/v1/account/balances?account_id=acct_example_main'timestamp=$(date +%s)signature=$(node --input-type=module - "$timestamp" "$request_path" <<'JS'import { sign } from './rest-client.mjs';console.log(sign(process.env.TRADE8_API_SECRET, process.argv[2], 'GET', process.argv[3]));JS)curl --fail-with-body "https://api.trade8.xyz$request_path" \ -H "X-Trade8-API-Key: $TRADE8_API_KEY" \ -H "X-Trade8-Timestamp: $timestamp" \ -H "X-Trade8-Signature: $signature"unset signatureRotate a Key
Section titled “Rotate a Key”Issue a replacement with the same minimum permissions, load it into the secret manager, and restart the relevant clients. Verify private reads, reconnect authenticated WebSocket sessions, then revoke the old key through your account’s access process. Separate signing credentials from application logs and support attachments.
WebSocket authentication uses the same HMAC function with a purpose-specific payload. See Connection and Authentication.