Stripe Integration for Subscription Management

Stripe is a powerful payment platform that enables businesses to process payments, manage subscriptions, and handle billing efficiently. This guide provides a step-by-step walkthrough of integrating Stripe into a subscription-based platform, covering setup, checkout sessions and webhook events.

Setting Up the Checkout Process:

The checkout process is where users select their plan and proceed to make payments. Stripe simplifies this through its checkout.sessions.create API, allowing you to generate a secure, prebuilt checkout page. Let’s break it down into simple steps:

  1. Creating a Stripe Customer :

Before allowing a user to make payments, it's a good idea to create a customer in Stripe. Think of this as a profile in Stripe’s system that keeps track of the user's information, like their email address and payment details.

Why is this important?

Creating a Stripe customer lets you:

  • Store the user’s details for future billing.
  • Handle upgrades, downgrades, or cancellations easily.
  • Link all payment activities (subscriptions, invoices) to the same user.

Here’s how you can do it with Stripe’s API:

let newCustomer = await stripe.customers.create({
  email: userEmail, // This should be the user's email address
})
const customerId = newCustomer.id // Save ID in database for later use

What’s happening here?

  1. You’re calling the Stripe API to create a new customer with the user’s email address.
  2. Stripe responds with a unique customerId that identifies this customer.
  3. Save this customerId in your database, so you can use it in the future (e.g., for creating subscriptions or sending invoices).

The customerId should be associated with the corresponding user in the database.

  1. Creating a Checkout Session :

Once you have a customer, the next step is to let them pick a plan and pay for it. This is done using a checkout session, which generates a payment page hosted by Stripe. You don’t have to worry about designing or securing this page—it’s all handled by Stripe.

To create a checkout session, you’ll need a few key pieces of information:

  • Price ID: This is the ID of the subscription plan you’ve set up in Stripe.
  • Quantity: How many subscriptions the user is buying (usually 1 for most cases).
  • Customer ID: The ID you saved earlier.
  • Success URL: Where users are redirected after a successful payment.
  • Cancel URL: Where users are redirected if they abandon the payment.

Here’s an example in JavaScript:

let checkoutSession = await stripe.checkout.sessions.create({
  payment_method_types: ['card'], // Accept card payments
  mode: 'subscription', //Specify the payment mode (subscription in this case)
  line_items: [
    {
      price: '<<price_id>>', // Replace with your actual price ID from Stripe
      quantity: 1, // Number of subscriptions
    },
  ],
  customer: customerId, //Link the session to the customer we created earlier
  success_url: `${process.env.NEXT_URL}/success`, //send users on success
  cancel_url: `${process.env.NEXT_URL}/cancel`, //send users if they cancel
})

Breaking it down:

  1. Payment Method : You tell Stripe what payment methods you’re accepting. Here, it’s "card", but you could also add methods like ACH or Apple Pay depending on your setup.
  2. Mode : You’re telling Stripe this is for a subscription, not a one-time payment.
  3. Line Items : This defines what the user is paying for. You include the priceId (e.g., monthly subscription) and the quantity.
  4. URLs : You specify where to redirect users after they finish or abandon the payment process. After running this code, Stripe will give you a checkoutSession.id and a URL for the hosted payment page. You can send your users to this page to complete the payment.

Handling Webhook Events

Stripe sends webhook events to notify your application of changes, such as successful payments or subscription updates. Properly handling these events is essential for keeping your system synchronized.

What Are Webhooks?

In simple terms, a webhook is a way for one system to send real-time data to another system. In the context of Stripe, when something happens (like a successful payment or a subscription cancellation), Stripe sends a notification (the webhook) to your server with detailed information about that event.

You can think of webhooks as a way for Stripe to “ping” your server whenever something important happens related to a customer’s subscription or payment.

  1. Setting Up a Webhook Listener :

To start using webhooks, you need to set up a webhook listener on your server. This is a specific URL endpoint where Stripe can send events.

const sig = req.headers.get('stripe-signature') as string;
 const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
 let event: Stripe.Event;
 try {
 if (!sig || !webhookSecret) return;
 event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
 ;
 } catch (err: any) {
 console.log(`
 ❌
 Error message: ${err.message}`);
 return new Response(`Webhook Error: ${err.message}`, { status: 400 });
 }

Stripe sends an event signature (stripe-signature) along with each webhook. This signature is a way to ensure that the event actually came from Stripe and hasn’t been tampered with. In the example above, we use stripe.webhooks.constructEvent() to verify the signature and process the event securely.

Once the webhook is set up and verified, Stripe will send various types of events to your server depending on what happens with the user’s payment or subscription.

  1. Handling Specific Events :

Handling 'invoice.payment_succeeded'

When a customer successfully makes a payment, Stripe triggers the invoice.payment_succeeded event. This is an important event because it confirms that a payment for a subscription has been processed successfully.

Here’s how you can handle this event:

const handlePaymentSucceeded = (event) => {
  const invoice = event.data.object // The invoice object contains details about the payment
  const customerId = invoice.customer
  const subscriptionId = invoice.subscription

  // Collect relevant information about the subscription
  const returnObject = {
    subscriptionId,
    customerId,
    nextPaymentDate: new Date(invoice.period_end * 1000), // Convert Unix timestamp to date
  }

  // You can now update your database with the subscription details
  updateSubscriptionInDatabase(returnObject)
}

Explanation:

  • Invoice Object: This contains all the payment details, including the customer ID, subscription ID, the next payment date, and more.

  • Updating the Database: After confirming the payment, you’ll want to update your database with this new information to reflect that the subscription is active.

Handling 'customer.subscription.deleted' :

When a customer cancels their subscription, Stripe sends the customer.subscription.deleted event. This event informs you that a user’s subscription has been terminated, and you may want to update your database accordingly.

Here’s how to handle it:

const handleSubscriptionDeleted = (event) => {
  const subscription = event.data.object
  const subscriptionId = subscription.id

  // Update your database to reflect the canceled subscription
  cancelSubscriptionInDatabase(subscriptionId)
}

Explanation:

  • Subscription Object : The customer.subscription.deleted event includes the subscriptionId, which you’ll use to locate the canceled subscription in your database and mark it as inactive.

Handling 'customer.subscription.updated' :

This event occurs when a subscription is updated, such as when the customer changes their plan or if a subscription is set to cancel at the end of the billing period.

Here’s how to handle it:

const handleSubscriptionUpdated = (event) => {
  const subscription = event.data.object
  const cancelAtPeriodEnd = subscription.cancel_at_period_end

  // If the subscription is set to cancel, handle it accordingly
  if (cancelAtPeriodEnd) {
    // Mark the subscription for cancellation at the end of the current billing cycle
    updateSubscriptionCancellationInDatabase(subscription.id)
  }
}

Explanation:

  • cancel_at_period_end : This property tells you if the subscription is scheduled to be canceled at the end of the billing cycle. If it's true, you might want to update your system to reflect that the user will lose access after the current period ends.

Thanks for reading, and take care!