Developers often describe payment integration as complex for two main reasons: first, it involves asynchronous payment confirmation, and second, payments often encounter various error scenarios. Additionally, handling money can make people uneasy.
I highly recommend using Stripe Checkout, the simplest way to accept payments for your SaaS product. With the Stripe Checkout API, you can create a checkout session by passing in your product line items with price, currency, and other details.
Remember to capture the session ID for tracking the subscription later. To keep things simple, we’re bypassing webhooks by calling the API to fetch the subscription during login. This approach streamlines the payment integration process.
The STRIPE_PRICE_ID
environment variable is set after creating our subscription product and pricing in Stripe. This
guide focuses on the system design rather than on setting up products, pricing, or fetching keys.
export async function handleCheckout(session, account) {
const stripeSession = await createCheckoutSession(session);
account.stripeSessionId = stripeSession.id;
// Save it to the database to fetch the status later.
redirect(stripeSession.url);
}
export async function createCheckoutSession(session) {
const stripe = new Stripe(process.env.STRIPE_KEY);
return await stripe.checkout.sessions.create({
customer_email: session.user.email,
payment_method_types: ["card"],
mode: "subscription",
line_items: [
{
price: process.env.STRIPE_PRICE_ID,
quantity: 1,
},
],
success_url: `${process.env.BASE_URL}/settings`,
cancel_url: `${process.env.BASE_URL}/settings`,
});
}
Since we cannot get the subscription ID directly in the checkout session, we need to retrieve the session to access the subscription ID in the subscription field. This allows us to verify if there is an active subscription.
Below is the code to check for subscription during login.
const stripeSession = await retrieveCheckoutSession(account);
if (stripeSession.status === "complete") {
account.stripeCustomerId = stripeSession.customer;
account.stripeSubscriptionId = stripeSession.subscription;
const isSubscribed = await checkActiveSubscription(account);
// Take action based on the isSubscribed boolean.
}
export async function retrieveCheckoutSession(account) {
const stripe = new Stripe(process.env.STRIPE_KEY);
return await stripe.checkout.sessions.retrieve(account.stripeSessionId);
}
export async function checkActiveSubscription(account) {
const stripe = new Stripe(process.env.STRIPE_KEY);
const stripeSubscription = await stripe.subscriptions.retrieve(
account.stripeSubscriptionId
);
return stripeSubscription.status === "active";
}
In an upcoming blog post, we’ll explore how we implemented Stripe integration for our E-commerce app.