The payload has to stay byte-for-byte stable
Stripe-style signatures are sensitive to the exact signed string. If a framework parses JSON, changes whitespace, or reserializes the body before verification, the HMAC can fail even when the secret and header are correct.
- Read the raw request body before JSON parsing.
- Build the signed string with the provider timestamp exactly as documented.
- Compare against every signature value present in the header.
- Keep the endpoint signing secret separate from account API keys.
Timestamp checks are part of the security model
A signature that matches an old payload should still fail when the timestamp is outside the allowed tolerance. The verifier should return a distinct replay-protection reason so teams do not mistake an expired event for a bad secret.
- Pass a trusted current timestamp into repeatable tests.
- Use a narrow tolerance window for production receivers.
- Return reason values such as valid, signature_mismatch, missing_header, and timestamp_out_of_tolerance.
- Avoid logging full payloads or signing secrets while debugging.
Use a diagnostic before touching production
A small verification API can turn one opaque failure into named checks: header found, timestamp parsed, expected signature calculated, signature matched, and replay window accepted.