Security Best Practices
Secure your GaiaEx API integration: credential management, IP whitelisting, key rotation intervals, and audit logging for production systems.
Security Best Practices
API key security is your responsibility. A compromised key can execute trades against your deposited balance and read your account data. It cannot move funds off the platform — withdrawals, deposits, and on-chain transfers all require the user's embedded-wallet signature plus a passkey step-up, which are only available in the mobile app. This guide covers battle-tested practices used by institutional trading desks.
NEVER HARDCODE CREDENTIALS
Never paste API keys or secrets directly into source code, scripts, notebooks, or commit them to version control. A single leaked credential in a public GitHub repo can be exploited within minutes by automated scanners.
Credential Separation with config.json
The recommended approach is to store credentials in a separate config.json file that is never committed to version control.
Step 1: Create config.json
{
"api_key": "a1b2c3d4e5f6789012345678abcdef00",
"api_secret": "s3cr3t_k3y_n3v3r_sh4r3_th1s_w1th_4ny0n3",
"user_address": "0xA6E3c04eF78427b5B53F43CDBA881d7E15B0bccD",
"base_url": "https://openapi.gaiaex.com/v1/trade"
}Step 2: Add to .gitignore
# .gitignore
config.json
*.secret
.env
.env.*Step 3: Load in Your Code
Python:
import json
with open("config.json") as f:
config = json.load(f)
API_KEY = config["api_key"]
API_SECRET = config["api_secret"]
ADDRESS = config["user_address"]JavaScript / Node.js:
const fs = require('fs');
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
const API_KEY = config.api_key;
const API_SECRET = config.api_secret;
const ADDRESS = config.user_address;Rust:
use serde::Deserialize;
use std::fs;
#[derive(Deserialize)]
struct Config {
api_key: String,
api_secret: String,
user_address: String,
}
let cfg: Config = serde_json::from_str(
&fs::read_to_string("config.json")?
)?;PROVIDE A TEMPLATE
Distribute a config.example.json with placeholder values so collaborators know the expected format without exposing real credentials.
{
"api_key": "PASTE_YOUR_API_KEY_HERE",
"api_secret": "PASTE_YOUR_API_SECRET_HERE",
"user_address": "0xYOUR_WALLET_ADDRESS",
"base_url": "https://openapi.gaiaex.com/v1/trade"
}Environment Variables
For CI/CD pipelines, Docker containers, and cloud deployments, environment variables are the standard approach.
# Set in your shell profile, .env file, or CI secrets
export GAIAEX_API_KEY="a1b2c3d4e5f6789012345678abcdef00"
export GAIAEX_API_SECRET="s3cr3t_k3y_n3v3r_sh4r3_th1s"
export GAIAEX_ADDRESS="0xA6E3c04eF78427b5B53F43CDBA881d7E15B0bccD"Python:
import os
API_KEY = os.environ["GAIAEX_API_KEY"]
API_SECRET = os.environ["GAIAEX_API_SECRET"]| Method | Best For | Risk Level |
|---|---|---|
config.json | Local development, personal bots | Low (if .gitignore'd) |
| Environment variables | CI/CD, Docker, cloud servers | Low |
| Hardcoded in source | Never | Critical — never do this |
IP Whitelisting
Lock your API key to specific IP addresses. Even if the key leaks, it cannot be used from unauthorized locations.
{
"ip_whitelist": ["203.0.113.50", "198.51.100.0/24"]
}Configure IP whitelisting when creating an API key via the GaiaEx mobile app or the POST /api-keys endpoint.
| Scenario | Recommendation |
|---|---|
| VPS/dedicated server | Whitelist the server's static IP |
| Home connection | Use a VPN with a static IP, then whitelist that |
| CI/CD pipeline | Whitelist your CI provider's IP range |
| Development (dynamic IP) | Use a separate dev key with read-only permissions |
TIP
If your IP changes frequently, create two API keys: one locked-down key for production (with IP whitelist + trade permission), and one read-only key for development (no IP restriction, read-only permission).
Permission Scoping (Principle of Least Privilege)
GaiaEx API keys support granular permissions. Only grant the minimum permissions needed.
| Permission | Allows | Use Case |
|---|---|---|
read | View balances, positions, orders, market data | Monitoring dashboards, analytics bots |
trade | Place, cancel, modify orders; close positions | Trading bots, strategy execution |
Recommendation:
- Monitoring scripts →
["read"]only - Trading bots →
["read", "trade"] - Never create "all permissions" keys unless absolutely necessary
Key Rotation
Rotate API keys regularly — especially after team member departures, suspected leaks, or security incidents.
Rotation Procedure
- Create a new key via the GaiaEx app or
POST /api-keys - Update your config.json or environment variables with the new key
- Verify the new key works (call
GET /timeorGET /health) - Revoke the old key via
DELETE /api-keys/{key_id}
Recommended rotation schedule:
| Scenario | Frequency |
|---|---|
| Production trading bot | Every 30–90 days |
| After team member leaves | Immediately |
| After suspected leak | Immediately |
| Development / testing key | Every 90 days |
Audit & Monitoring
Monitor your API key activity for unauthorized access.
- Check the audit log via
GET /api-keys/{key_id}/audit— shows all API calls made with that key - Monitor order history — unexpected orders may indicate compromised keys
- Set up alerts — use User Data Stream WebSocket to get real-time notifications of trades and balance changes
What to Watch For
| Signal | Action |
|---|---|
| API calls from unknown IPs | Rotate key immediately, enable IP whitelist |
| Orders you didn't place | Revoke key, cancel all orders, secure wallet |
| Authentication failures spike | Someone may be brute-forcing — enable IP whitelist |
| Rate limit hits you didn't cause | Your key may be in use elsewhere — rotate |
Security Checklist
| # | Item | Status |
|---|---|---|
| 1 | Credentials in config.json or environment variables — never hardcoded | ☐ |
| 2 | config.json is in .gitignore | ☐ |
| 3 | IP whitelist enabled for production keys | ☐ |
| 4 | Minimum permissions granted (read-only where possible) | ☐ |
| 5 | API keys rotated every 30–90 days | ☐ |
| 6 | Separate keys for production and development | ☐ |
| 7 | Audit logs reviewed weekly | ☐ |
| 8 | config.example.json template committed for team reference | ☐ |
| 9 | WebSocket user stream connected for real-time trade monitoring | ☐ |