An agent workflow waits for a provider webhook before marking a payment complete. A middleware change parses the incoming JSON, then serializes it again before the signature check. The object is semantically the same, but whitespace, property order or numeric formatting can differ. The signature covers the provider's original bytes under its signing scheme, not our reconstructed JSON object. Stripe's webhook guidance explicitly requires the raw request body for signature verification.

Capture the raw body and signature header at the HTTP boundary. Verify with the configured endpoint secret and the provider's timestamp and tolerance rules before trusting event fields. Only then parse and dispatch. The trusted secret comes from the configured provider endpoint, not from a field in the payload. If the same application handles several webhook endpoints or tenants, bind the event to the correct endpoint secret and account. A successful JSON parse is not authentication.

There is a dangerous “fix” to avoid: disabling verification because production webhooks started failing. That accepts arbitrary posts at an action-completion endpoint. Instead, check whether the proxy or framework changed encoding, decompressed the body, normalized newlines, or consumed the stream before verification. Compare a captured raw test event before and after the refactor without logging sensitive payloads broadly.

Verified events can still arrive more than once or out of order. Deduplicate using provider event identity, make the workflow transition idempotent, and reconcile the provider's authoritative resource state when event order matters. Signature verification answers “who sent these bytes under this secret,” not “has this event already been applied” or “is this the latest payment state.”

If an interviewer asks why re-serializing cannot be canonicalized, it could be if both sides explicitly agreed on one canonical format and signed that representation. Most webhook contracts instead specify the raw transmitted payload. Implement the contract you actually receive, not a different signing protocol invented in middleware.