Signing API requests is a critical step when interacting with cryptocurrency exchanges like OKEx (now known as OKX). If done incorrectly, you’ll encounter authentication errors such as "invalid sign" or "invalid timestamp." This guide walks you through the correct process of generating a valid signature for OKEx API requests, using clear examples in Python and Postman, while addressing common pitfalls and best practices.
Whether you're building a trading bot, syncing wallet balances, or automating trades, understanding how to properly authenticate your API calls ensures seamless integration with the exchange.
Understanding OKEx API Authentication
OKEx uses HMAC-SHA256 signatures for securing API endpoints. Each private request must include several headers:
OK-ACCESS-KEY: Your API key.OK-ACCESS-SIGN: The Base64-encoded HMAC-SHA256 signature.OK-ACCESS-TIMESTAMP: ISO 8601 formatted timestamp (e.g.,2025-04-05T07:09:47.123Z).OK-ACCESS-PASSPHRASE: The passphrase set during API key creation.Content-Type: Usuallyapplication/json.
The signature is generated by concatenating:
timestamp + method + request_path + bodyThen signing this message with your Secret Key using HMAC-SHA256 and encoding the result in Base64.
🔐 The Secret Key should never be exposed in client-side code or logs. Always store it securely using environment variables or secure vaults.
Step-by-Step Python Implementation
Below is a refined version of the original code that correctly signs an OKEx API request to fetch spot account balances.
import hmac
import base64
import requests
from datetime import datetime
# Load sensitive data securely (replace with environment variables)
API_KEY = 'your_api_key'
SECRET_KEY = 'your_secret_key'
PASSPHRASE = 'your_passphrase'
def get_timestamp():
"""Fetch current time from OKX server to ensure accuracy."""
url = 'https://www.okx.com/join/BLOCKSTARapi/v5/public/time'
response = requests.get(url)
if response.status_code == 200:
data = response.json()
return data['data'][0]['ts'] # Unix timestamp in milliseconds
else:
# Fallback to local time if needed (not recommended for production)
return str(int(datetime.utcnow().timestamp() * 1000))
def iso_timestamp(ts_ms):
"""Convert millisecond timestamp to ISO format."""
seconds = int(ts_ms) / 1000
return datetime.utcfromtimestamp(seconds).isoformat() + 'Z'
def sign_request(timestamp, method, request_path, body, secret_key):
"""
Generate HMAC-SHA256 signature encoded in Base64.
Args:
timestamp (str): ISO8601 timestamp
method (str): HTTP method (GET, POST, etc.)
request_path (str): API endpoint path
body (str): Request body string (empty if none)
secret_key (str): Your API secret key
Returns:
str: Base64-encoded signature
"""
if body is None:
body = ''
message = timestamp + method.upper() + request_path + body
mac = hmac.new(
bytes(secret_key, 'utf-8'),
bytes(message, 'utf-8'),
digestmod='sha256'
)
return base64.b64encode(mac.digest()).decode('utf-8')
def create_headers(method, request_path, body=''):
"""Build complete authorization headers."""
ts_ms = get_timestamp()
timestamp = iso_timestamp(ts_ms)
signature = sign_request(timestamp, method, request_path, body, SECRET_KEY)
return {
'OK-ACCESS-KEY': API_KEY,
'OK-ACCESS-SIGN': signature,
'OK-ACCESS-TIMESTAMP': timestamp,
'OK-ACCESS-PASSPHRASE': PASSPHRASE,
'Content-Type': 'application/json'
}
# Example: Fetch spot account balance
url = 'https://www.okx.com/join/BLOCKSTARapi/v5/account/balance'
headers = create_headers('GET', '/api/v5/account/balance')
response = requests.get(url, headers=headers)
print(response.status_code)
print(response.json())👉 Generate highly secure and reliable API signatures with real-time timestamp validation.
Common Mistakes and How to Avoid Them
Even small deviations can lead to failed authentication. Here are frequent issues developers face:
1. Incorrect Timestamp Format
Using local system time instead of the exchange's server time often results in "timestamp expired" errors. Always use /api/v5/public/time to get the exact time.
2. Body Handling
For GET requests without a body, ensure you pass an empty string ('') — not None or '{}'. Including unnecessary JSON formatting breaks the signature.
3. Case Sensitivity
HTTP methods must be uppercase (GET, POST). Lowercase values invalidate the signature.
4. Secret Key Encoding
Ensure UTF-8 encoding when converting the secret key and message into bytes. Mismatched encoding leads to incorrect hashes.
5. URL Path vs Full URL
Only include the request path (e.g., /api/v5/account/balance) — never the full URL or query parameters unless part of the actual path.
👉 Access accurate server timestamps and enhance your API request reliability.
Using Postman for Testing
Postman is ideal for testing private endpoints before integrating into your application.
Steps:
- Set up a GET request to:
https://www.okx.com/join/BLOCKSTARapi/v5/account/balance Add headers:
OK-ACCESS-KEY: Your API KeyOK-ACCESS-PASSPHRASE: Your PassphraseContent-Type:application/jsonOK-ACCESS-TIMESTAMP: {{timestamp}}OK-ACCESS-SIGN: {{sign}}
In Pre-request Script, add:
pm.sendRequest('https://www.okx.com/join/BLOCKSTARapi/v5/public/time', function (err, res) { const data = res.json(); const ts = data.data[0].ts; const isoTimestamp = new Date(parseInt(ts)).toISOString(); pm.environment.set("timestamp", isoTimestamp); const message = isoTimestamp + 'GET' + '/api/v5/account/balance'; const sign = CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256(message, 'your_secret_key_here') ); pm.environment.set("sign", sign); });
Now every request will auto-generate valid credentials.
Frequently Asked Questions (FAQ)
Q: Why do I get "Invalid Sign" even with correct credentials?
A: Double-check that your message string exactly matches: timestamp + method + path + body. Even extra spaces or wrong casing will break it.
Q: Can I use local time for the timestamp?
A: It’s risky. OKX allows only a small clock drift (usually ±30 seconds). Use their public time endpoint for precision.
Q: What should I do if my Secret Key is exposed?
A: Immediately log in to your OKX account and revoke the compromised API key. Generate a new one with limited permissions.
Q: Does the body need to be JSON stringified?
A: Yes — but only for POST/PUT requests. For GET requests, use an empty string.
Q: Are query parameters included in the request path?
A: Yes — if your endpoint includes queries like /orders?limit=10, include the full path including ?limit=10.
Q: Is HMAC-SHA256 supported in all programming languages?
A: Yes — libraries exist for Python (hmac), JavaScript (CryptoJS), Java (javax.crypto), and more.
👉 Explore advanced API tools and streamline your development workflow today.
Final Tips for Secure and Reliable Integration
- Rate Limits: OKX enforces rate limits based on user tier. Design your app with exponential backoff logic.
- Environment Separation: Use demo trading APIs for testing before going live.
- Error Logging: Log HTTP status codes and error messages but never log secrets.
- Two-Factor Security: Enable IP whitelisting and 2FA on your API keys for added protection.
By following this guide, you’ll be able to sign OKEx (OKX) API requests accurately and securely across different platforms and programming languages.
Core Keywords: OKEx API, sign API request, HMAC-SHA256, Base64 encoding, timestamp authentication, API security, cryptocurrency trading API