Webhooks are a crucial part of integrating with Stripe. They enable Stripe to send real-time notifications about events happening in your Stripe account, such as successful payments, failed payments, or subscription updates. This allows your Next.js application to react dynamically to these events without requiring constant polling. In this section, we'll cover how to set up and handle Stripe webhooks in your Next.js application.
Why Use Webhooks?
Webhooks are essential for several reasons:
- Real-time Updates: Get notified instantly when a payment is completed, refunded, or fails. This is vital for fulfilling orders or updating user statuses promptly.
- Reliability: Stripe reliably delivers webhook events. If your server is temporarily down, Stripe will retry sending the event until it's successfully received.
- Security: Webhooks help prevent race conditions and ensure that your application's state is always synchronized with Stripe's. For example, you can automatically grant access to a digital product only after a payment is confirmed via a webhook.
- Automation: Automate critical business logic based on payment outcomes, such as sending confirmation emails, updating internal databases, or provisioning services.
Setting Up a Webhook Endpoint in Next.js
To receive webhook events, you need to create an API route in your Next.js application that Stripe can send POST requests to. We'll use the pages/api/webhooks/stripe.js (or app/api/webhooks/stripe/route.js if using the App Router) convention for this.
This API route will listen for incoming POST requests from Stripe. Inside this route, we'll parse the event and take appropriate actions.
import { buffer } from 'micro';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
if (req.method === 'POST') {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
await buffer(req),
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.log(`Webhook signature verification failed.`, 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 for ${paymentIntent.amount} was successful!`);
// Fulfill the purchase, send an email, etc.
break;
case 'payment_intent.payment_failed':
const failedPaymentIntent = event.data.object;
console.log(`PaymentIntent failed: ${failedPaymentIntent.last_payment_error.message}`);
// Notify the user, log the error, etc.
break;
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`);
}
// Return a 200 response to acknowledge receipt of the event
res.status(200).json({ received: true });
} else {
res.setHeader('Allow', 'POST');
res.status(405).end('Method Not Allowed');
}
}