Payload Signing
All order requests and responses must include an HMAC SHA256 signature in the x-pch-digest header to ensure payload integrity.
Signature Generation (For Responses)
Algorithm: HMAC SHA256
Key: First 10 characters of SharedId
Payload Format: Pipe-delimited string
RequestUid|LocationId|OnlineOrderId|GrandTotalCents|SubtotalCents|ReceivedAtSeconds
Steps:
-
Extract the first 10 characters of
SharedIdas the HMAC key. -
Build payload string from order data:
RequestUid: Order request UIDLocationId: Location identifierOnlineOrderId: Online order ID (use "0" if null)GrandTotalCents: Total in cents (multiply by 100, round to long)SubtotalCents: Subtotal in cents (multiply by 100, round to long)-
ReceivedAtSeconds: Unix timestamp in seconds fromrequest_datetime(format:yyyy-MM-ddTHH:mm:ss.fffZ)
-
Compute HMAC SHA256 hash.
-
Convert to a lowercase hexadecimal string.
-
Add to
x-pch-digestresponse header.
Example Implementation (C#):
public static string CalculateOrderSignature(OrderResponse order, string sharedId)
{
if (string.IsNullOrWhiteSpace(sharedId) || sharedId.Length < 10)
throw new ArgumentException("SharedId must be at least 10 characters");
string key = sharedId.Substring(0, 10);
long grandTotalCents = (long)((order.OrderDetails?.GrandTotal ?? 0) * 100);
long subtotalCents = (long)((order.OrderDetails?.Subtotal ?? 0) * 100);
// Parse datetime (format: yyyy-MM-ddTHH:mm:ss.fffZ) to Unix seconds
long receivedAtSeconds = 0;
if (DateTimeOffset.TryParse(order.RequestDateTime, out var dto))
{
receivedAtSeconds = dto.ToUnixTimeSeconds();
}
var payloadParts = new List<string>
{
order.RequestUid ?? "0",
order.LocationId ?? "0",
order.OrderDetails?.OnlineOrderId ?? "0",
grandTotalCents.ToString(),
subtotalCents.ToString(),
receivedAtSeconds.ToString()
};
string payload = string.Join("|", payloadParts);
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
return Convert.ToHexString(hashBytes).ToLowerInvariant();
}
Signature Validation (for Requests)
- Extract
x-pch-digestheader from incoming request. - Recalculate the signature using the same algorithm.
- Compare the calculated signature with the header value (case-insensitive).
- Reject the request if the signatures do not match.
