DEV Community

Apollo
Apollo

Posted on

How I built a Stripe Webhook in Node.js (Full Guide)

How I Built a Stripe Webhook in Node.js (Full Guide)

Stripe webhooks are essential for handling asynchronous events in payment processing systems. They allow your application to respond to events like successful payments, failed charges, or subscription cancellations in real-time. In this guide, I'll walk you through building a robust Stripe webhook endpoint in Node.js, complete with event validation and error handling.

Prerequisites

Before diving into the implementation, ensure you have the following:

  1. A Stripe account (sign up here)
  2. Node.js installed (preferably version 14 or higher)
  3. Basic knowledge of JavaScript and Node.js
  4. Stripe CLI for testing webhooks locally

To install the Stripe CLI:

brew install stripe/stripe-cli/stripe
Enter fullscreen mode Exit fullscreen mode

Setting Up Your Node.js Project

First, create a new Node.js project:

mkdir stripe-webhook
cd stripe-webhook
npm init -y
Enter fullscreen mode Exit fullscreen mode

Next, install the necessary dependencies:

npm install express body-parser stripe
Enter fullscreen mode Exit fullscreen mode

Creating the Webhook Endpoint

Let's start by creating a basic Express server with a webhook endpoint.

Step 1: Initialize Express Server

Create a file named server.js and add the following code to set up an Express server:

const express = require('express');
const bodyParser = require('body-parser');
const stripe = require('stripe')('your_stripe_secret_key'); // Add your Stripe secret key

const app = express();
app.use(bodyParser.json());

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Step 2: Add the Webhook Endpoint

Now, add the webhook endpoint. Stripe requires you to verify the event's authenticity using the stripe-signature header.

const endpointSecret = 'your_webhook_signing_secret'; // Add your Stripe webhook signing secret

app.post('/webhook', async (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}`);
  }

  // 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;
    // Add more cases for other event types as needed
    default:
      console.log(`Unhandled event type: ${event.type}`);
  }

  res.json({ received: true });
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Testing the Webhook Locally

To test the webhook locally, use the Stripe CLI to forward events to your endpoint:

stripe listen --forward-to localhost:3000/webhook
Enter fullscreen mode Exit fullscreen mode

Trigger a test event from the Stripe Dashboard or using the Stripe CLI:

stripe trigger payment_intent.succeeded
Enter fullscreen mode Exit fullscreen mode

You should see the event being logged in your terminal.

Handling Complex Events

In a production environment, you might need to handle more complex events, such as subscription lifecycle events or invoice payments. Here's an example of handling a subscription creation event:

case 'customer.subscription.created':
  const subscription = event.data.object;
  console.log('Subscription created:', subscription.id);
  // Implement your logic here, e.g., update user subscription status in your database
  break;
Enter fullscreen mode Exit fullscreen mode

Error Handling and Logging

Robust error handling is crucial for production-ready webhooks. Implement logging for better debugging and monitoring:

app.post('/webhook', async (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}`);
  }

  try {
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object;
        console.log('PaymentIntent was successful:', paymentIntent.id);
        break;
      // Add more cases
      default:
        console.log(`Unhandled event type: ${event.type}`);
    }
  } catch (err) {
    console.error(`Event handling error: ${err.message}`);
    return res.status(500).send('Internal Server Error');
  }

  res.json({ received: true });
});
Enter fullscreen mode Exit fullscreen mode

Securing Your Webhook Endpoint

Ensure your webhook endpoint is secure:

  1. Use HTTPS in production.
  2. Keep your Stripe secret keys and webhook signing secrets secure.
  3. Validate the stripe-signature header for every event.

Deployment

Deploy your Node.js application to a cloud provider like Heroku, AWS, or Google Cloud. Ensure your webhook URL is correctly set in the Stripe Dashboard.

Conclusion

Building a Stripe webhook in Node.js involves setting up an Express server, validating incoming events, and handling them appropriately. By following this guide, you can create a robust webhook endpoint capable of handling various Stripe events securely and efficiently.

Happy coding! 🚀


🚀 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)