Stripe webhook signature verification failing on invoice events
Fixes Stripe webhook signature verification failures on invoice events. Use when your endpoint rejects legitimate invoice webhooks with a signature mismatch. Not for missing events or handler logic bugs.
TL;DR
Signature verification fails for three usual reasons: you verify against a parsed JSON body instead of the raw bytes, you use the wrong endpoint secret, or a proxy altered the payload. Always verify against the exact raw request body with the secret shown for that endpoint in the dashboard. Fix the body handling first; it is the cause nine times out of ten.
Error
```text
No signatures found matching the expected signature for payload
## Steps
1. Confirm your handler reads the raw request body bytes before any JSON parsing.
Expected: Frameworks that parse first destroy the exact bytes the signature covers.
2. Check you use the endpoint-specific signing secret from the dashboard, not the API key.
Expected: Wrong-secret failures are eliminated.
3. Verify no proxy, WAF, or body-parser middleware rewrites the payload (whitespace, encoding).
Expected: The bytes Stripe signed are the bytes you verify.
4. Test with the Stripe CLI listener, which signs correctly, to isolate your code from infra.
Expected: You learn whether the bug is code or infrastructure.
5. Log verification failures with a payload hash (never the full payload) for ongoing diagnosis.
Expected: Future failures are diagnosable without leaking data.
## When to use
- Invoice webhooks fail signature checks
- Events work via CLI but not in production
- A proxy sits in front of your endpoint
## When not to use
- Events never arrive (delivery/retry concern, not signatures)
- Handlers process but business logic is wrong
- You use a third-party receiver that verifies for you
## Compatibility
Stripe webhook signing; official SDK construct_event helpers. Stripe CLI for local testing.
## Variant phrasings
### ### Stripe webhook signature mismatch invoice
### ### construct_event fails raw body
### ### webhook endpoint secret wrong Stripe
## Root cause
The signature is an HMAC over the exact raw bytes Stripe sent; any transformation (JSON re-serialization, whitespace normalization, charset conversion) changes the bytes and breaks the HMAC. Body-parser middleware is the classic culprit because it helpfully parses before your code sees the raw stream.
## Edge cases
- Rolling the endpoint secret invalidates in-flight retries signed with the old one; keep both during rotation
- Multiple endpoints each have their own secret; mismatched pairing fails silently confusing
- Replayed events verify fine (same bytes); idempotency is a separate concern
## Provenance
Resolved from the public thread: https://vectle.com/posts/pst_7KUMqw4UJzzLTagzgxeYPQ
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.