HMAC stands for Hash-based Message Authentication Code, and is described here: https://en.wikipedia.org/wiki/HMAC, but essentially it's a cryptographically secure hash value generated based on a computed value and a pre-shared key.
HMAC signing is enabled by associating an HMAC secret with the API key - this will be either an API user or an API integration. Once a secret is set, valid HMAC signatures must accompany every API request.
The HMAC signature should be sent in a custom HTTP Header named X-PX-Request-ID>. This header should be built using the following values concatenated together, in this order:
/merchant/30/restaurants/pxweb/menu/tier?key=9dxxxxxfe843bbxxxxxcd9xxxxxf88d850xxxxxOnce this string is generated, the following operations should be performed on it to get the message signature:
X-PX-Request-IDRequest URI: https://od.pxsweb.com/api/v1/merchant/30/restaurants/pxweb/menu/tier?key=9dxxxxxfe843bbxxxxxcd9xxxxxf88d850xxxxx Body: None Timestamp: 1583254634525 Value to be hashed: 1583254634525/merchant/30/restaurants/pxweb/menu/tier?key=9dxxxxxfe843bbxxxxxcd9xxxxxf88d850xxxxx Base64 encoded hash result: 4iX2WnHGrCL2fIc2V9zOH2z2SY/UswsQS+MQSmlrlN8= Header without base64-encoding: 1583254634525;4iX2WnHGrCL2fIc2V9zOH2z2SY/UswsQS+MQSmlrlN8= Actual header to be sent: X-PX-Request-ID: MTU4MzI1NDYzNDUyNTs0aVgyV25IR3JDTDJmSWMyVjl6T0gyejJTWS9Vc3dzUVMrTVFTbWxybE44PQ==
Request URI: https://od.pxsweb.com/api/v1/orders/xxxxx/items?key=9dxxxxxfe843bbxxxxxcd9xxxxxf88d850xxxxx
Body: {"id":"xxx","quantity":1,"size":""}
Timestamp: 1583254967310
Value to be hashed: 1583254967310/orders/xxxxx/items?key=9dxxxxxfe843bbxxxxxcd9xxxxxf88d850xxxxx{"id":"xxx","quantity":1,"size":""}
Base64 encoded hash result: uE9rkxYON1+FU+SWVrRVTZFpO04w0IUvkm28GWF7hI=
Header without base64-encoding: 1583254967310;EuE9rkxYON1+FU+SWVrRVTZFpO04w0IUvkm28GWF7hI=
Actual header to be sent:
X-PX-Request-ID: MTU4MzI1NDk2NzMxMDtFdUU5cmt4WU9OMStGVStTV1ZyUlZUWkZwTzA0dzBJVXZrbTI4R1dGN2hJPQ==
The following Javascript implements this algorithm in Javascript as a Postman Pre-request Script
// 1. Get timestamp in milliseconds
var timestampMs = new Date().getTime();
// 2. Get all of url, including query parameters, following /api/v1
var fullUrl = pm.variables.replaceIn(pm.request.url.toString());
var partialUrl = fullUrl.match(/\/api\/v1(.*)$/)[1];
// 3. Get request body, if one exists
var requestBody = pm.request.body.raw || '';
// 4. Concatenate
var rawHeader = ''.concat(timestampMs, partialUrl, requestBody);
// 5. Create binary HMAC using your secret and encode binary result in base64
var signBytes = CryptoJS.HmacSHA256(rawHeader, pm.variables.get('hmac_secret'));
var signBase64 = CryptoJS.enc.Base64.stringify(signBytes);
// 6. Concatenate timestamp, a semicolon and the base64 signed value and base64 encode the result
var hmacBase64 = btoa(''.concat(timestampMs, ';', signBase64));
// 7. Set custom header with final header value
pm.request.headers.add({
key: "X-PX-Request-ID",
value: hmacBase64
});