Accessing Stripe Webhooks with Vercel, Supabase, and React.js
Integrating Stripe webhooks into your React.js application powered by Vercel and Supabase can be a tricky dance. This article breaks down the process, offering a clear path to successfully capturing and handling these critical events.
The Challenge
Stripe webhooks are powerful tools, enabling real-time updates on events within your Stripe account. However, receiving and processing these webhooks securely and efficiently within a serverless environment like Vercel, while storing data in Supabase, can be daunting.
Scenario
Imagine you have a React.js application that processes online payments through Stripe. You want to be notified when a customer successfully completes a payment. To achieve this, you need to configure Stripe webhooks to send data to your application when a checkout.session.completed
event occurs.
Original Code (Partial)
// Stripe webhook handler (serverless function)
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
exports.handler = async (event, context) => {
const signature = event.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(event.body, signature, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
console.error(err);
return {
statusCode: 400,
body: JSON.stringify({ error: 'Webhook signature verification failed.' }),
};
}
// Process event data based on type
if (event.type === 'checkout.session.completed') {
// Store data in Supabase
}
}
Breaking it Down
- Vercel Serverless Function: The code snippet defines a serverless function deployed on Vercel. This function acts as the endpoint for Stripe webhooks.
- Signature Verification: The
stripe.webhooks.constructEvent
function validates the incoming webhook data using the providedstripe-signature
header and your Stripe webhook secret. This ensures the data originates from Stripe and hasn't been tampered with. - Data Processing: Once verified, the webhook data is processed based on the
event.type
. - Supabase Integration: The code snippet suggests storing the processed data in Supabase.
Key Considerations
- Security: Verifying the webhook signature is crucial. Never trust the data directly without validation.
- Scalability: Vercel provides a serverless environment, making it easy to scale your webhook handling infrastructure as your user base grows.
- Data Persistence: Supabase offers a robust and flexible PostgreSQL database, allowing you to store and query webhook data efficiently.
- Real-Time Updates: You can utilize Supabase's real-time capabilities to trigger updates in your React.js application based on changes in the webhook data.
Example Implementation
Here's a refined example showcasing the integration with Vercel, Supabase, and React.js:
1. Vercel Serverless Function
// serverless.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const { createClient } = require('@supabase/supabase-js');
const supabaseUrl = process.env.SUPABASE_URL;
const supabaseKey = process.env.SUPABASE_KEY;
const supabase = createClient(supabaseUrl, supabaseKey);
exports.handler = async (event, context) => {
const signature = event.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(event.body, signature, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
console.error(err);
return {
statusCode: 400,
body: JSON.stringify({ error: 'Webhook signature verification failed.' }),
};
}
if (event.type === 'checkout.session.completed') {
const { data: { id: sessionId } } = event.data.object;
try {
const { error } = await supabase
.from('payment_events')
.insert({ session_id: sessionId, event_type: 'checkout.session.completed' });
if (error) {
console.error('Error storing data in Supabase:', error);
}
} catch (error) {
console.error(error);
}
}
return {
statusCode: 200,
body: JSON.stringify({ received: true }),
};
};
2. React.js Component
import React, { useEffect, useState } from 'react';
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL;
const supabaseKey = process.env.REACT_APP_SUPABASE_KEY;
const supabase = createClient(supabaseUrl, supabaseKey);
function PaymentEvents() {
const [paymentEvents, setPaymentEvents] = useState([]);
useEffect(() => {
const subscription = supabase
.from('payment_events')
.on('*', (payload) => {
setPaymentEvents((prevEvents) => [...prevEvents, payload.new]);
})
.subscribe();
return () => subscription.unsubscribe();
}, []);
return (
<div>
<h1>Payment Events</h1>
<ul>
{paymentEvents.map((event) => (
<li key={event.id}>
Session ID: {event.session_id}, Event Type: {event.event_type}
</li>
))}
</ul>
</div>
);
}
export default PaymentEvents;
3. Setting up Stripe Webhooks
- In your Stripe dashboard, navigate to Developers > Webhooks.
- Create a new webhook endpoint with the URL of your Vercel function.
- Select the
checkout.session.completed
event, ensuring the signature is correctly configured.
Conclusion
This article provides a comprehensive guide to efficiently integrating Stripe webhooks into your Vercel and Supabase powered React.js application. By following these steps, you can receive real-time payment updates, process data securely, and utilize a powerful serverless architecture for robust and scalable webhook handling.