Webhook Signature Verification

Signature verification uses the Stripe-Signature header and your endpoint's signing secret to prove a webhook really came from Stripe and wasn't tampered with.

Webhook signature verification is how you confirm that an incoming webhook genuinely came from Stripe and hasn't been altered. Because your webhook endpoint is a public URL, anyone could POST fake data to it — verifying the signature is what keeps you from acting on a forged event.

How it works

Stripe signs every webhook and includes the signature in the Stripe-Signature header, along with a timestamp. To verify:

  1. Take the raw request body exactly as received, the Stripe-Signature header, and your endpoint's signing secret (the value starting with whsec_).
  2. Pass them to Stripe's constructEvent helper (or compute the HMAC yourself).
  3. If the signature matches, the event is authentic; if not, reject the request.
Verified = HMAC(raw body + timestamp, signing secret) matches the header signature

Each endpoint has its own signing secret, and test and live-mode endpoints have different ones — verifying against the wrong secret is a common failure.

Two things that trip people up

  • Use the raw body. Any reformatting or re-serialization of the payload before verification breaks the signature. Read the body as raw bytes before your framework parses it.
  • Timestamp tolerance. The signed timestamp defends against replay attacks. Stripe's libraries reject events older than a default tolerance (5 minutes), so a badly out-of-sync server clock can cause valid events to fail.

Running verification correctly is fiddly — raw-body handling, secret management, clock skew. ChargeBell handles all of it on your behalf, so you get trustworthy Stripe alerts in Slack without writing or maintaining any verification code.

Related terms

Updated July 6, 2026