Tools
Stripe webhook checker
A delivery can fail because Stripe never called you, or because you rejected a signature. This page explains that split, then checks a signature locally.
What the Dashboard is telling you
No delivery
The event exists and this endpoint was not called. The URL is the preview host, the event type is not selected, or you are looking at the other mode.
400 from your URL
Stripe called you and the signature check failed, or your code rejected the payload. Compare the secret and the raw body before you rotate anything else.
500 or a timeout
The signature may be fine. The handler threw, or an edge function did too much work after verify. Return a non-2xx only when you want Stripe to retry, and record the event id first.
Check a signature in the browser
Fix it
Open the failing delivery in Stripe
Read the URL, the response code, and the response body. A missing delivery is a wrong endpoint. A 400 is often the signature. A 500 is your handler.
Copy the signing secret for that endpoint and mode
Test and live endpoints do not share a secret. The secret in a local env file is not evidence about production.
Paste the header and the raw body here
Use the Stripe-Signature header and the exact payload. The page computes the HMAC in your browser and tells you whether v1 matches.
Fix the handler if the signature is valid
If this page matches and production does not, production is hashing different bytes or using a different secret. Check raw-body parsing and the deployed env.
Questions
Does FunnelWatch receive the signing secret?
No. The check runs in your browser with Web Crypto. The secret and the body are not posted to FunnelWatch. Do not use this page on a computer you do not trust.
The signature matches and it still says the timestamp is old.
Stripe recommends rejecting timestamps outside five minutes. An event you copied from the Dashboard is older than that. A match with a stale timestamp means the secret and the body agree, and a live handler should still reject the event.
Why does a pretty-printed body fail?
Stripe signs the raw bytes. Parsing JSON and printing it again changes the bytes. Paste the exact payload from the delivery.