Sending a webhook is easy. You POST some JSON at a URL and move on.
Receiving one is where the bodies are buried. The endpoint is public, so anyone can call it. It gets retried, so it will run twice. It arrives out of order, so "delivered" can land before "sent". And it is on the critical path of somebody else's system, so if you are slow they will time out and retry, which makes you slower.
None of this is hard once you know it. All of it is invisible until production. Here is the complete set of things a webhook receiver has to handle, with the failure each one prevents.
The running example is email delivery webhooks (bounces and complaints), because they happen to have every awkward property at once: they are security-sensitive, they retry, they arrive out of order, and processing one twice corrupts real state. Everything here applies just as well to Stripe, GitHub, Shopify or anything else that calls you back.
1. Verify the signature, on the raw body






