Webhooks are essential for keeping your Stripe integration in sync with your application. They allow Stripe to send real-time notifications to your server about events, such as successful payments, failed charges, or subscription updates. This section will guide you through testing and handling Stripe webhooks in your Next.js application.
Why are webhooks so important? In an e-commerce scenario, you can't rely solely on the user seeing a 'Payment Successful' page. A webhook confirms the payment on the server-side, enabling you to fulfill the order, grant access to digital goods, or trigger other business logic securely.
During development, you need a way to simulate Stripe sending webhooks to your local Next.js server. Stripe CLI is the recommended tool for this. It allows you to forward events from your Stripe test environment directly to your local machine.
First, ensure you have the Stripe CLI installed. You can find installation instructions on the Stripe website. Once installed, you can log in to your Stripe account using stripe login.
Next, you'll need to set up a webhook endpoint in your Next.js application. This will be a dedicated API route that Stripe can send POST requests to. Let's create a file at pages/api/webhooks.js.
export default async function handler(req, res) {
if (req.method === 'POST') {
const payload = req.body;
const signature = req.headers['stripe-signature'];
// Verify the webhook signature (crucial for security!)
// ... verification logic here ...
const event = payload;
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
// TODO: Fulfill the order, update database, etc.
break;
case 'payment_intent.payment_failed':
const failedPaymentIntent = event.data.object;
console.log('Payment failed:', failedPaymentIntent.last_payment_error.message);
// TODO: Notify the customer, update UI, etc.
break;
// ... handle other event types ...
default:
console.log(`Unhandled event type ${event.type}`);
}
res.status(200).json({ received: true });
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}