Skip to content
Last updated

Quick summary

  • 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

Base URL

EnvironmentBase URL
Sandboxhttps://api.banxa-sandbox.com/eapi/v0/
Productionhttps://api.banxa.com/eapi/v0/

Authorization header

Every request must include:

Authorization: Bearer API_KEY:SIGNATURE:NONCE
ComponentDescription
API_KEYPublic API key provided during onboarding
SIGNATUREHex-encoded HMAC-SHA256 signature
NONCEUnix timestamp in milliseconds

Building the signature

Construct a newline-separated canonical string, then sign it with HMAC-SHA256 using your API secret.

GET request:

METHOD\nPATH_WITH_QUERY_STRING\nNONCE

POST request:

METHOD\nPATH\nNONCE\nCOMPACT_JSON_BODY

Rules:

  • 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"}

Code examples

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}', nonce
const 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

Authentication errors

CodeCause
40001Nonce is not a valid Unix timestamp in milliseconds
40002Nonce is too old — check your system clock is in sync
40003Nonce already used — generate a new nonce per request
40100API key not recognised — check you are using the correct environment key
40101Authorization header is malformed — format must be Bearer API_KEY:SIGNATURE:NONCE
40102Authorization header is missing
40103Signature mismatch — check path, newline separators, compact JSON, and correct secret

Best practices

  • 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_id from error responses for debugging

If issues persist, contact your Banxa Account Manager.