I can't respond to this comment directly because it is dead, but that is an important thing to call out. We have replay protection built into the libraries. The signature contains a timestamp, a unique webhook id for the event, the recipient id, and the target endpoint’s url and method.
The verify function returns an error if the timestamp is expired or if the recipient id or target url are not as expected. The timestamp check is standard for any type of signature. The recipient id and target url check is unique to asymmetric signatures and prevents a situation where one user can forward their requests or trick the webhook producer into sending requests to a different user.
If extra protection is desired, the webhook id is returned to the consumer after they verify the request and can be used to guarantee that a webhook can only be received once (eg. throw the webhook ids in redis with a ttl longer than the signature ttl and reject any requests with webhook ids that have already been seen).