BackendWebhooksNode.jsExpressStripeBackend

Building a Webhook System with Node.js and Express

Design and implement a robust webhook system in Node.js — receiving, verifying, processing, and retrying webhook events reliably.

Abdur Razzak

Abdur Razzak

Full-Stack Web Developer

April 27, 2025 10 min read

What Are Webhooks?

Webhooks are HTTP callbacks that services send to your server when events occur. Instead of polling an API repeatedly to check for changes, webhooks push data to you in real time. Stripe sends a webhook when a payment succeeds. GitHub sends a webhook when code is pushed. Building a reliable webhook receiver is a critical skill for integrating with third-party services in MERN stack development.

Receiving and Verifying Webhooks

Create an Express endpoint at /api/webhooks/stripe (or whatever service). Use express.raw({ type: 'application/json' }) middleware (not express.json()) for Stripe webhooks — you need the raw body buffer to verify the signature. Most services sign their webhooks with HMAC-SHA256 using a signing secret. Always verify the signature before processing — ignore unsigned or invalid webhook requests.

Processing Webhooks Reliably

Return a 200 response immediately after verifying the webhook signature — before processing the event. If your processing logic takes too long, the sender will retry the webhook (thinking it timed out). Queue the event in Redis or a message queue (Bull, BullMQ) for asynchronous processing. Process events idempotently — if the same event is delivered twice, processing it twice should not cause duplicate side effects.

Idempotency with Event IDs

Webhook providers always retry failed deliveries, so your handler must be idempotent. Store each processed event ID in your database. Before processing a new event, check if its ID already exists — if so, skip processing and return 200. This prevents duplicate orders, double-charging customers, or creating duplicate records when webhooks are retried after a temporary server error.

Building a Webhook Delivery System

If you need to send webhooks from your own application to customers, build a delivery system: store webhook endpoints in your database, send events using axios with a timeout, log the response status, and retry failed deliveries with exponential backoff (1 min, 5 min, 30 min, 2 hours, 24 hours). Provide a webhook event log UI so customers can see delivery history and manually retry failed events.

Testing Webhooks Locally

Use the Stripe CLI (stripe listen --forward-to localhost:3000/api/webhooks/stripe) or ngrok to forward webhook events to your local development server. This lets you test the complete webhook flow without deploying to a staging server. Install the Stripe CLI and trigger test events with stripe trigger payment_intent.succeeded to simulate real webhook payloads during development.

Share this article

All posts
#Webhooks#Node.js#Express#Stripe#Backend
Abdur Razzak — Full Stack Web Developer

Free Consultation

Got a Project Idea? Let's Talk.