Code a Stripe Subscription Model With React and Nextjs
Stripe subscriptions are a great way to monetize your AI tool. We'll show you how to set up a subscription model using React and NextJS
Posted by
Marc LouRelated reading
Stripe Subscriptions Explained With a Real-World Example
Let's set up up and manage a subscription model for a fictional habit tracker app called Trackify.
Introduction
Subscriptions are the lifeline of many online businesses. They provide predictable revenue and help shape a loyal user base. For your landing page generator app (AI tool), charging $15 per month, we'll guide you through setting up Stripe Subscriptions using NextJS.
If you want a more in-depth guide on how Stripe Subscriptions work, check out our Stripe Subscriptions Explained article.
Setting Up Stripe Subscriptions
No code yet! Start by configuring your Stripe account:
- Register an account at Stripe and sign in.
- Add your landing page generator as a new product under the "Products" section in Stripe.
- Create a monthly subscription plan for $15 in the "Pricing" section of your product.
- Note down the API keys from the "Developers" section for later use.
Creating a Stripe Checkout Session
To handle payments, you'll need a Stripe Checkout session. This calls for some coding:
// install with npm install stripe
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export default async (req, res) => {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price: 'price_xxx', // replace with your price ID
quantity: 1,
}],
mode: 'subscription',
success_url: 'https://yourdomain.com/success',
cancel_url: 'https://yourdomain.com/cancel',
});
res.redirect(303, session.url);
};
Place the above serverless function within your NextJS project to initiate checkout sessions.
Handling Subscriptions on the Frontend
Create a subscription button on your app's frontend to allow users to start the checkout process. When clicked, it should call your serverless function to create a Stripe Checkout session:
// Replace with your actual API endpoint
const checkoutUrl = 'https://api.yourdomain.com/create-checkout-session';
const subscribeUser = async () => {
const res = await fetch(checkoutUrl);
const { url } = await res.json();
window.location.href = url;
};
// Usage in your component
<button onClick={subscribeUser}>Subscribe Now</button>
Handling Subscription Webhook Events
Once your checkout session is complete, you will need to handle subscription changes. Stripe uses webhooks to notify you of subscription events in real time. In your landing page generator, you should listen for these events to activate or deactivate user subscriptions accordingly.
Setting Up Your Webhook Listener
Create a serverless function in your Vercel project to listen for Stripe webhook events:
export default async (req, res) => {
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
if (req.method === 'POST') {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} 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 'checkout.session.completed':
const session = event.data.object;
// Handle checkout session completion, provide access
break;
case 'invoice.paid':
// Continue to provision the subscription as payments keep coming in
break;
case 'invoice.payment_failed':
// The payment failed or the subscription has a problem, alert the user, or revoke access
break;
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`);
}
// Return a 200 response to acknowledge receipt of the event
res.json({ received: true });
} else {
res.setHeader('Allow', 'POST');
return res.status(405).end('Method Not Allowed');
}
};
Activating and Deactivating User Subscriptions
When handling these webhook events, you'll want to update user's subscription status in your own system. For example:
// pseudo-code: activate or deactivate user based on Stripe webhook event
function manageUserSubscription(event) {
if (event.type === 'checkout.session.completed') {
// Find user by checkout session ID or customer ID
// Activate their subscription in your system
} else if (event.type === 'customer.subscription.deleted' || event.type === 'invoice.payment_failed') {
// Find user and deactivate subscription in your system
}
// Other webhook events can be handled similarly
}
Remember to protect your webhook endpoint. Only Stripe should be calling this function, so verify the event with stripe.webhooks.constructEvent
as shown above. Also, ensure that your Stripe secret and endpoint secrets are stored securely and not hardcoded into your codebase.
By setting up webhook handling properly, you ensure that your application remains in sync with the reality of your users' subscription status on Stripe.
Cancellation and Refunds
Provide users the ability to cancel their subscriptions from within your app. Tie this front-end feature to a backend operation that alters the subscription status in Stripe:
// Serverless function to cancel subscription
export default async (req, res) => {
const { subscriptionId } = req.body;
const deleted = await stripe.subscriptions.del(subscriptionId);
res.json({ confirmed: deleted });
};
Remember to clearly define your refund policy and execute refunds through the Stripe API or Dashboard as needed.
Summary
Throughout this guide, we have encapsulated how to utilize Stripe Subscriptions for a $15 monthly landing page generator.
Key takeaways include setting up subscriptions, leveraging Stripe for automated billing, responding to payment events with webhooks, and securely adapting to subscription changes via a Next.js serverless function.