Webhooks arrive more than once, and out of order
A note on Webhooks by Stripe, published on docs.stripe.com.
Reading a provider's webhook documentation as a general specification is an underrated habit, and Stripe's is the best written of them.
Four obligations come out of it, and they generalise to every provider. Verify the signature, because an endpoint that accepts unsigned payloads is an endpoint anyone can post to. Acknowledge quickly, because the provider is measuring your response time and will redeliver if you are slow. Do the real work asynchronously, because the acknowledgement and the processing are different concerns. And expect duplicates, because at-least-once delivery means exactly what it says.
The fourth is the one people design around last and should design around first. Retries are not an error condition; they are normal operation. A handler that is only correct when each event arrives once is a handler that is incorrect, it just has not been caught yet.
The practical value of reading the docs rather than a blog post is that the edge cases are enumerated by people who see every failure mode across a very large number of integrations. The blog post tells you the idea. The docs tell you what actually goes wrong.
This is the thinking behind the questions I ask before writing billing code.