How I Built a Stripe Webhook in Node.js (Full Guide)
Webhooks are essential for modern SaaS applications, enabling real-time communication between services. In this guide, I'll walk you through building a Stripe Webhook in Node.js, ensuring secure, scalable, and robust processing of Stripe events. By the end, you’ll have a fully functional webhook implementation ready for production.
Why Webhooks?
Webhooks allow Stripe to notify your application about events like payment success, subscription cancellations, or charge disputes. Instead of polling Stripe’s API, webhooks push data to your server, making your app more efficient and responsive.
Prerequisites
Before diving in, ensure you have:
- Node.js installed (v16+ recommended).
- A Stripe account with API keys (test mode is sufficient for development).
- An HTTP server framework like Express.
- A tool like ngrok to expose your local server for testing.
Step 1: Set Up Your Node.js Project
Start by initializing a Node.js project:
mkdir stripe-webhook
cd stripe-webhook
npm init -y
Install the required dependencies:
npm install express stripe body-parser
Step 2: Create a Basic Express Server
Create an index.js file and set up a basic Express server:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.send('Stripe Webhook Server');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Run the server:
node index.js
Step 3: Set Up Stripe Webhook Endpoint
Next, create a /webhook endpoint to handle incoming Stripe events:
const stripe = require('stripe')('your_stripe_secret_key');
const endpointSecret = 'your_webhook_signing_secret';
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.error(`Webhook Error: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
console.log('Received event:', event.type);
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log('PaymentIntent was successful:', paymentIntent.id);
break;
case 'charge.failed':
const charge = event.data.object;
console.log('Charge failed:', charge.id);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.json({ received: true });
});
Step 4: Secure Your Webhook
Stripe uses signatures to verify the authenticity of webhook events. The stripe.webhooks.constructEvent function validates the payload using the Stripe-Signature header and your webhook signing secret.
Never expose your Stripe secret key or webhook signing secret in client-side code.
Step 5: Test Your Webhook Locally
Use ngrok to expose your local server:
ngrok http 3000
Update your Stripe webhook settings in the Stripe Dashboard with the ngrok URL (e.g., https://your-ngrok-url.ngrok.io/webhook).
Trigger a test event in Stripe’s Dashboard to verify it works.
Step 6: Handle Common Webhook Scenarios
Here are some common scenarios you might handle:
1. Payment Succeeded
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log('Payment succeeded:', paymentIntent.id);
break;
2. Subscription Created
case 'customer.subscription.created':
const subscription = event.data.object;
console.log('Subscription created:', subscription.id);
break;
3. Charge Failed
case 'charge.failed':
const charge = event.data.object;
console.log('Charge failed:', charge.id);
break;
Step 7: Deploy Your Webhook
Once tested, deploy your webhook to a production server (e.g., AWS, Heroku, or Vercel). Update your Stripe webhook settings with the production URL.
Best Practices
- Idempotency: Ensure your webhook handlers are idempotent to handle duplicate events gracefully.
- Logging: Log all incoming events for debugging and auditing.
- Rate Limiting: Protect your endpoint from abuse by implementing rate limiting.
- Retry Logic: Handle failed events by retrying with exponential backoff.
Conclusion
Building a Stripe webhook in Node.js is straightforward with the stripe-node SDK and Express. By following this guide, you’ve created a secure and scalable webhook endpoint ready to handle Stripe events in real time.
Experiment with different event types and integrate them into your application’s workflow. Happy coding! 🚀
Further Reading:
🚀 Stop Writing Boilerplate Prompts
If you want to skip the setup and code 10x faster with complete AI architecture patterns, grab my Senior React Developer AI Cookbook ($19). It includes Server Action prompt libraries, UI component generation loops, and hydration debugging strategies.
Browse all 10+ developer products at the Apollo AI Store | Or snipe Solana tokens free via @ApolloSniper_Bot.
Top comments (0)