Best Practices for Receiving Webhooks
The reliable way to receive webhooks is to verify the signature, write the event somewhere durable, return a 2xx within a few seconds, and do the real work in a background job. Senders retry on timeouts and on any non-2xx response, so a slow handler produces duplicate deliveries rather than lost ones.
Receiving webhooks reliably
Reliability on the receiving side is a response-time problem before it is anything else.
Most providers give an endpoint 5 to 30 seconds before they mark the delivery failed: Shopify allows 5, GitHub 10, Stripe 20.
So acknowledge first and process second. Verify the signature, check the delivery's webhook-id against your deduplication store, append the raw body to a queue, and return 200.
Everything expensive belongs to a worker.
Assume at-least-once delivery rather than exactly-once. A sender that never sees your 200, because the connection dropped after you had already committed the event, sends the same event again, and only the receiver can tell that it is the same event. Webhook timeout best practices covers the queue-and-worker split in detail.
Security first
The first layer of securing your webhook receptions is verifying the signature. Most webhooks are secured via a webhook signature, and the responsibility lies on the receiver to ensure they verify this signature with the pre-shared key. It's simple, but skipping it is the single most common webhook security mistake. Providers that follow the Standard Webhooks specification all sign the same way and send the same headers, so one verification library covers every compliant sender.
But what if someone manages to obtain a payload that was signed with the correct key and tries to re-transmit it to you? That's where protection from replay attacks comes in.
The first line of defense against this is a timestamp. Most webhook senders, including Svix, Stripe, and others, include a timestamp. The receiver's job is to ensure that the webhook was sent within a reasonable time frame, let's say within five minutes before or after the current time. This measure offers substantial protection against replay attacks.
If you use Svix libraries, the above steps are conveniently handled for you. You can read more about how Svix handles webhook signatures in our documentation.
Idempotency
Idempotency matters for both security and operational integrity.
Implementations like Svix, among others, send a unique identifier in the header (webhook-id under Standard Webhooks, which recommends exactly this deduplication).
What you should do as a receiver is store this identifier, perhaps in Redis or any other suitable environment, and use it to track whether you've already processed a message with that identifier.
This step helps prevent handling the same message twice, either due to a replay attack or an integrity issue.
Handling replay attacks
Imagine your webhook is structured to add $100 to an account whenever a referral is made. In the absence of proper replay attack protection, an attacker can trigger the resending of the same event multiple times, resulting in multiple unwarranted credit transactions. This is why protection against replay attacks is vital.
Receiving from different sources
When dealing with different sources, it's best to treat them as distinct entities. Just as a GitHub API and a Stripe API aren't the same thing, neither are their webhooks. Therefore, have different URLs or paths for different webhooks. This not only ensures operational integrity but also simplifies log analysis and statistics.
Handling different event types
Finally, for different event types from the same source, filter the event types on the sender side. This reduces the amount of noise hitting your endpoints and optimizes your operations. Then, internally, you can create a basic router to check the event types and send them to different handlers.
Where you can be flexible
As long as the sender handles retries properly, a receiver can afford the occasional bad minute: a deploy, a database failover, or a worker restart all resolve themselves on the next delivery attempt. Signature verification, timestamp checks, and deduplication are the parts that have no second chance, so those are the ones to get right first.
Ready to send webhooks?
Svix handles signing, retries, rate limiting, and delivery observability for the webhooks you send to your users, so your team can stay focused on your product.
Start sending webhooks with Svix or read the build vs. buy analysis