How to Sign OKEx API Requests Correctly

·

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:

The signature is generated by concatenating:

timestamp + method + request_path + body

Then 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:

  1. Set up a GET request to:
    https://www.okx.com/join/BLOCKSTARapi/v5/account/balance
  2. Add headers:

    • OK-ACCESS-KEY: Your API Key
    • OK-ACCESS-PASSPHRASE: Your Passphrase
    • Content-Type: application/json
    • OK-ACCESS-TIMESTAMP: {{timestamp}}
    • OK-ACCESS-SIGN: {{sign}}
  3. 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

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