Paste the raw request body, the shared secret and the signature you received, and this computes the HMAC and compares them. It is the check every webhook receiver has to do and the one that most often fails on the first attempt for a reason that has nothing to do with the cryptography.
Almost always because the payload changed before it was hashed. The signature covers the exact bytes that arrived, so a receiver that parses the JSON and re-serialises it before hashing is signing a different string — key order, whitespace and number formatting all shift. Capture the raw body first and hash that. The other frequent cause is a signature header that carries a prefix ("sha256=") or a different encoding, hex versus base64.
In production, compare with a constant-time function — crypto.timingSafeEqual in Node, hmac.compare_digest in Python. A normal string comparison returns on the first differing byte, and the timing difference is enough to reconstruct a valid signature given enough attempts. This page compares in constant time too, though against a secret you pasted yourself it is a demonstration rather than a defence.
A validly signed payload stays validly signed forever, so anyone who captures one can replay it. Real webhook providers sign a timestamp alongside the body and expect receivers to reject anything older than a few minutes. If the provider gives you a timestamp, it is part of the signed string, not a header to ignore.