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:

  1. Extract the first 10 characters of SharedId as the HMAC key.

  2. Build payload string from order data:

  • RequestUid: Order request UID
  • LocationId: Location identifier
  • OnlineOrderId: 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 from request_datetime (format: yyyy-MM-ddTHH:mm:ss.fffZ)
  1. Compute HMAC SHA256 hash.

  2. Convert to a lowercase hexadecimal string.

  3. Add to x-pch-digest response 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)

  1. Extract x-pch-digest header from incoming request.
  2. Recalculate the signature using the same algorithm.
  3. Compare the calculated signature with the header value (case-insensitive).
  4. Reject the request if the signatures do not match.
signature_validation.png