5 min read

How to implement Stripe Subscriptions

Everything you need to know without getting lost in the Stripe official documentation.

Why this guide?

The best marketing win of Stripe was convincing the world that they have "the best documentation". The amount of times I see this parrot-like comment on Reddit is astounding.

Unfortunately, Stripe supports many use cases, so there is no single "right way" to do things. Depending on what you google or where you end up in the documentation, you might end up implementing something overly complex or inadequate.

This guide is an opinionated tutorial about how to implement Subscriptions for people who have never implemented Stripe.

Which Products should you use?

Implement subscriptions with Stripe Billing and Checkout Sessions.

Summary:

  • 1.When your user clicks "subscribe", your backend creates a custom link (aka checkout session).
  • 2.You redirect the user to that link, which is a Stripe hosted checkout page where they can input their payment details.
  • 3.When the payment succeeds, the user gets automatically redirected back to your site.

This hosted page is the same many big companies like ChatGPT use. You probably recognize the design.

This is the beautifully created interactive documentation from Stripe you should check. Note that you can select your frontend/backend framework on top to see the right code for you:

https://docs.stripe.com/payments/quickstart-checkout-sessions

Easiest implementation

The raw Stripe documentation doesn't cover the use case 99% of the people need: Users need to be logged in before they can subscribe, and you need to link the payment to the user_id in your application.

Linking user_id and customer.id

Every payment in Stripe needs to be associated with a Customer object. If you don't explicitly create a customer, it will be automatically created by Stripe.

The right pattern to implement this is to explicitly create a Stripe customer in your backend before creating a checkout session:

1. User clicks subscribe

2. Your backend creates a Stripe Customer

const customer = await stripe.customers.create({
  email: user.email,
});

3. Your backend stores the relation between user_id and the customer.id you just created (e.g. in your database)

4. Your backend creates a checkout session passing the customer ID

const checkout = await stripe.checkout.sessions.create({
  customer: customer.id,
  ...
});

Webhooks

The source of truth of your payments and subscriptions stays in Stripe. However, you cannot call the Stripe API any time you want updated information because you will get rate limited.

Stripe forces you to sync data to your local database using webhooks, but there are over 250 event types.

You will need to configure these webhooks in Stripe and listen to them in your backend. If you are using Next.js, we built an npm package that handles all the logic for you stripe-no-webhooks

Note: stripe-no-webhooks also has a utility to create checkout sessions without writing all the boilerplate.

If you want to handle webhooks yourself, you need to create a webhook in Stripe https://docs.stripe.com/webhooks

The webhooks affecting subscriptions are the following ones:

"checkout.session.completed",
"customer.subscription.created",
"customer.subscription.updated",
"customer.subscription.deleted",
"customer.subscription.paused",
"customer.subscription.resumed",
"customer.subscription.pending_update_applied",
"customer.subscription.pending_update_expired",
"customer.subscription.trial_will_end",
"invoice.paid",
"invoice.payment_failed",
"invoice.payment_action_required",
"invoice.upcoming",
"invoice.marked_uncollectible",
"invoice.payment_succeeded",
"payment_intent.succeeded",
"payment_intent.payment_failed",
"payment_intent.canceled",

Final remarks

We keep building and improving our tools for online payments. If you have any questions or ideas, don't hesitate to contact us, we also help with custom software projects.

Ramon Garate

Ramon Garate

LinkedInLinkedIn