Step 3: Authentication
The Banxa API implements an HMAC authentication strategy which requires the payload of the message to be hashed. The hashing of the payload needs to be correct, otherwise, the API request will be rejected.
Authorization Header
For all requests to the Banxa API, add an Authorization digest to the header. The header structure must be in the following format:
"Authorization: Bearer API Key:Signature:Nonce"
API Key
The API public key credential. This is the one provided by us during on-boarding.
Signature
Message authentication signature. The request message is hashed with the API Secret using SHA256 algorithm.
The structure of the message:
- Request method. (e.g. "GET or "POST")
- Request URI path including the query parameters for GET.
- The nonce value (e.g. using unix timestamp value)
- The payload in JSON format only for POST, with no whitespace.
Each of the items in the message should be separated by a new line for example
'GET' + '\n' + '/api/coins' + '\n' + '1612391416'
'POST' + '\n' + '/api/orders' + '\n' + '1612391416' + '\n' + '{"account_reference":"example_01"}'
Nonce
A unix timestamp in milliseconds generated for this request.
Sample Code
Here is some sample code around how to call the API including the HMAC authentication. Key things to note when building your integration:
- The signature passed to the HMAC algorithm are separated by new lines (see above section)
- The json payload for POST requests should contain no whitespace
- The nonce should be a unix timestamp which is generated for every request
import requests
import time
import hmac
url = 'https://[PARTNER-NAME].banxa-sandbox.com'
key = '[YOUR_MERCHANT_KEY]'
secret = '[YOUR_MERCHANT_SECRET]'
def generateHmac(payload, nonce):
hmacCode = hmac.digest(secret, payload.encode('utf8'), 'SHA256')
print(payload)
print(hmacCode.hex())
return key + ':' + hmacCode.hex() + ':' + str(nonce)
package com.banxa;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Formatter;
public class BanxaService {
private static final String BANXA_URL = "https://api.banxa-sandbox.com";
private static final String KEY = "[YOUR_MERCHANT_KEY]";
private static final String SECRET = "[YOUR_MERCHANT_SECRET]";
public String getHmac(String method, String query, String payload) throws Exception {
String nonce = String.valueOf(System.currentTimeMillis());
String data = method + "\n" +
query + "\n" +
nonce;
if (payload != null) {
data += "\n" + payload;
}
SecretKeySpec signingKey = new SecretKeySpec(SECRET.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
return KEY + ":" + toHexString(mac.doFinal(data.getBytes())) + ":" + nonce;
}
private String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
}
<?php
$url = "https://api.banxa-sandbox.com";
$key = '[YOUR_MERCHANT_KEY]';
$secret= '[YOUR_MERCHANT_SECRET]';
function generateHmac($payload, $nonce) {
$sign = hash_hmac('SHA256', $payload, $secret);
return $key.':'.$sign.':'.$nonce;
}
$nonce = time();
function generateHmac(signature, nonce) {
const crypto = require('crypto')
const key = '[YOUR_MERCHANT_KEY]'
const secret = '[YOUR_MERCHANT_SECRET]'
const localSignature = crypto.createHmac("SHA256", secret).update(signature).digest("hex");
return `${key}:${localSignature}:${nonce}`;
}
import CryptoKit
let key = "[YOUR_MERCHANT_KEY]"
let secret = "[YOUR_MERCHANT_SECRET]".data(using: .utf8)!
let secretKey = SymmetricKey(data: secret)
public func generateHmac(
method: String,
query: String,
data: Optional<String> = nil
) -> String {
let nonce = String(NSDate().timeIntervalSince1970).split(separator: ".")[0]
var payload = method + "\n" + query + "\n" + nonce
if((data) != nil) {
payload = payload + "\n" + (data!)
}
let payloadData = payload.data(using: .utf8)!
let hmac = HMAC<SHA256>.authenticationCode(for: payloadData, using: secretKey)
let hmacByteString = hmac.map { String(format: "%02hhx", $0) }.joined()
return key + ":" + hmacByteString + ":" + nonce
}
require 'openssl'
def generate_hmac(time, query, body, method = 'POST')
secret = API_SECRET
body_encoded = body.to_s if body
data = "#{method}\n#{query.to_s}\n#{time.to_s}\n#{body_encoded.to_s}"
digest = OpenSSL::Digest.new('sha256')
hmac = OpenSSL::HMAC.hexdigest(digest, secret, data)
"#{API_KEY}:#{hmac}:#{time.to_s}"
end
Authentication Error Codes
If you receive a 401 HTTP error when sending a request to the Banxa API, typically there is something wrong with your HMAC header. Here are some common reasons for certain error codes.
Error code starting with 400
- Code 40001 - this is normally when you are sending us a nonce that is not a valid unix timestamp. We do accept seconds, milliseconds and microseconds so please check your nonce is 10, 13 or 16 digits with no other characters.
- Code 40002 - this is normally if the nonce was generated too long before the request was sent or your system clock is not up to date.
- Code 40003 - we have seen this nonce before. Ensure you generate a new nonce for every request. To reduce the number of conflicts we do only check this one for POST requests and it used to avoid replay attacks.
Error code starting with 401
- Code 40100 - Check the API Key you have sent is for the correct environment and matches what we sent you
- Code 40101 - The Authorization header is malformed. Check again the format given above
- Code 40102 - The Authorization header is missing.
- Code 40103 - We were unable to generate the same signature to match the one sent on the Banxa side. Please ensure that you have followed the instructions to build the payload such as each piece of data is separated by a new line, the JSON payload has no whitespace between the elements and also that you are passing the secret and payload into the correct fields of your HMAC algorithm
- Code 40104 - Check the API Key you have sent is for the correct environment and matches what we sent you
If you cannot solve your issues with this help, then feel free to contact your Account Manager for support
Updated 2 months ago