Authentication
This API uses an HMAC‑SHA256 signature derived from the request path and the SHA256 digest of the request body. The final signature is folded multiple times and sent in the Authorization header together with your API account key.
Required Headers
X-Api-Key: <your API account key>
Authorization: HMAC <base64_signature>
Accept: application/json
What Gets Signed
The following steps show exactly how the signature is calculated. You can verify your implementation by reproducing the example below, which signs a request to create a supplier.
For this worked example:
- API Secret:
6OZ0oHt0y3ICVaje95yGrQtt - Folds:
5
Follow along to ensure your implementation produces the same output.
Step 1 - Canonical Path
Use the exact request path, including the leading slash and excluding any query parameters.
Example:
/api/v1/suppliers
Step 2 - Body Digest
Compute the SHA256 hash of the raw request body bytes, then encode the result as a lowercase hex string.
If the request has no body (e.g., GET), compute the SHA256 of the empty string "".
Example request body:
{"supplier":{"trading_name":"New Supplier Ltd","vendor_code":"NS002"}}
SHA256 digest:
e9bafdf140aed2d704843d1ec702fc360fca435470f4dc1cdb1a201dc20ae5d8
Step 3 - Build the String to Sign
Concatenate the canonical path and the body digest with no delimiter.
Example:
/api/v1/supplierse9bafdf140aed2d704843d1ec702fc360fca435470f4dc1cdb1a201dc20ae5d8
Step 4 - Fold the Digest (Repeated HMAC)
Perform the following operation five times (or your configured fold count):
stringToSign[i+1] = HMAC_SHA256_HEX(secret, stringToSign[i])
Each fold uses the hex output of the previous fold as its input.
Step 5 - Base64 Encode the Final Fold
Take the hex output of the final fold and Base64‑encode it:
YmQ5MzUyNTIxNGMyNmQ2ODdmNmFhNzQ1MTY1NjBmNWVhZTUwMmQ1OWEyODMwYWJiNDc5ZjY1NTYxOGMyMTA3OQ==
This is the final signature.
Step 6 - Build the Authorization Header
Insert the signature into the header exactly as follows:
Authorization: HMAC YmQ5MzUyNTIxNGMyNmQ2ODdmNmFhNzQ1MTY1NjBmNWVhZTUwMmQ1OWEyODMwYWJiNDc5ZjY1NTYxOGMyMTA3OQ==
Your request is now fully authenticated and ready to send.
Example Code (NodeJS)
const crypto = require("crypto");
const axios = require("axios");
async function generateSignature(path, payload, secretKey, folds) {
const payloadString = payload ? JSON.stringify(payload) : "";
const payloadHash = crypto
.createHash("sha256")
.update(payloadString)
.digest("hex");
const stringToSign = `${path}${payloadHash}`;
let signature = crypto
.createHmac("sha256", secretKey)
.update(stringToSign)
.digest("hex");
for (let i = 1; i < folds; i++) {
signature = crypto
.createHmac("sha256", secretKey)
.update(signature)
.digest("hex");
}
return Buffer.from(signature).toString("base64");
}
async function createSupplier() {
const API_SECRET_KEY = process.env.API_SECRET_KEY;
const API_SIGNATURE_FOLDS = parseInt(process.env.API_SIGNATURE_FOLDS, 10);
const API_ACCOUNT_KEY = process.env.API_ACCOUNT_KEY;
const url = "https://www.suppliermanagement.co.za/api/v1/suppliers";
const payload = {
supplier: {
trading_name: "New Supplier Ltd",
vendor_code: "NS002",
}
}
const path = new URL(url).pathname;
const base64Signature = await generateSignature(path, payload, API_SECRET_KEY, API_SIGNATURE_FOLDS);
try {
const response = await axios.post(
url,
payload,
{
headers: {
Accept: "application/json",
Authorization: `HMAC ${base64Signature}`,
'X-Api-Key': API_ACCOUNT_KEY,
},
}
);
console.log("Response:", response.data);
} catch (error) {
console.error("Error:", error.message);
}
}
createSupplier();