- Auth type: HMAC-SHA256
- Header:
Authorization: Bearer API_KEY:SIGNATURE:NONCE - Nonce: Unix timestamp in milliseconds, unique per request
- Signature: Hex-encoded HMAC-SHA256 of a newline-separated canonical string
| Environment | Base URL |
|---|---|
| Sandbox | https://api.banxa-sandbox.com/eapi/v0/ |
| Production | https://api.banxa.com/eapi/v0/ |
Every request must include:
Authorization: Bearer API_KEY:SIGNATURE:NONCE| Component | Description |
|---|---|
API_KEY | Public API key provided during onboarding |
SIGNATURE | Hex-encoded HMAC-SHA256 signature |
NONCE | Unix timestamp in milliseconds |
Construct a newline-separated canonical string, then sign it with HMAC-SHA256 using your API secret.
GET request:
METHOD\nPATH_WITH_QUERY_STRING\nNONCEPOST request:
METHOD\nPATH\nNONCE\nCOMPACT_JSON_BODYRules:
- Use the request path only — never the full URL with domain
- Include the query string in the path for GET requests
- JSON body must be compact — no whitespace between elements
- Generate a new nonce for every request
Examples:
GET\n/eapi/v0/price\n1612391416000
POST\n/eapi/v0/ramps\n1612391416000\n{"identityReference":"example_01"}import hmac
import time
key = '[YOUR_API_KEY]'
secret = '[YOUR_API_SECRET]'
def generate_hmac(method, path, payload=None):
nonce = str(int(time.time() * 1000))
parts = [method, path, nonce]
if payload:
parts.append(payload)
data = '\n'.join(parts)
signature = hmac.new(secret.encode('utf-8'), data.encode('utf-8'), 'sha256').hexdigest()
return f'{key}:{signature}:{nonce}', nonceconst crypto = require('crypto');
const key = '[YOUR_API_KEY]';
const secret = '[YOUR_API_SECRET]';
function generateHmac(method, path, payload = null) {
const nonce = Date.now().toString();
const parts = [method, path, nonce];
if (payload) parts.push(payload);
const data = parts.join('\n');
const signature = crypto.createHmac('sha256', secret).update(data).digest('hex');
return `${key}:${signature}:${nonce}`;
}<?php
$key = '[YOUR_API_KEY]';
$secret = '[YOUR_API_SECRET]';
function generateHmac($method, $path, $payload, $key, $secret) {
$nonce = (string)(time() * 1000);
$parts = [$method, $path, $nonce];
if ($payload) $parts[] = $payload;
$data = implode("\n", $parts);
$signature = hash_hmac('sha256', $data, $secret);
return "{$key}:{$signature}:{$nonce}";
}import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Formatter;
public class BanxaAuth {
private static final String KEY = "[YOUR_API_KEY]";
private static final String SECRET = "[YOUR_API_SECRET]";
public String generateHmac(String method, String path, String payload) throws Exception {
String nonce = String.valueOf(System.currentTimeMillis());
String data = method + "\n" + path + "\n" + nonce;
if (payload != null) data += "\n" + payload;
SecretKeySpec signingKey = new SecretKeySpec(SECRET.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
Formatter formatter = new Formatter();
for (byte b : mac.doFinal(data.getBytes())) {
formatter.format("%02x", b);
}
return KEY + ":" + formatter.toString() + ":" + nonce;
}
}import CryptoKit
let key = "[YOUR_API_KEY]"
let secret = "[YOUR_API_SECRET]"
func generateHmac(method: String, path: String, payload: String? = nil) -> String {
let nonce = String(Int(Date().timeIntervalSince1970 * 1000))
var parts = [method, path, nonce]
if let payload = payload { parts.append(payload) }
let data = parts.joined(separator: "\n")
let secretKey = SymmetricKey(data: secret.data(using: .utf8)!)
let signature = HMAC<SHA256>.authenticationCode(for: data.data(using: .utf8)!, using: secretKey)
.map { String(format: "%02hhx", $0) }.joined()
return "\(key):\(signature):\(nonce)"
}require 'openssl'
KEY = '[YOUR_API_KEY]'
SECRET = '[YOUR_API_SECRET]'
def generate_hmac(method, path, payload = nil)
nonce = (Time.now.to_f * 1000).to_i.to_s
parts = [method, path, nonce]
parts << payload if payload
data = parts.join("\n")
signature = OpenSSL::HMAC.hexdigest('sha256', SECRET, data)
"#{KEY}:#{signature}:#{nonce}"
end| Code | Cause |
|---|---|
| 40001 | Nonce is not a valid Unix timestamp in milliseconds |
| 40002 | Nonce is too old — check your system clock is in sync |
| 40003 | Nonce already used — generate a new nonce per request |
| 40100 | API key not recognised — check you are using the correct environment key |
| 40101 | Authorization header is malformed — format must be Bearer API_KEY:SIGNATURE:NONCE |
| 40102 | Authorization header is missing |
| 40103 | Signature mismatch — check path, newline separators, compact JSON, and correct secret |
- Generate a new nonce for every request
- Keep your system clock in sync (NTP)
- Always serialize JSON with no whitespace before signing
- Use the request path only — never the full URL with domain
- Log the
request_idfrom error responses for debugging
If issues persist, contact your Banxa Account Manager.