The easiest way to integrate Stripe
Jan 26, 2025
Ayush, Autumn Co-Founder
This article is based on Theo Browne's method for integrating Stripe—huge credit to him. Follow him on Twitter @theo and check out his site.
Stripe's APIs are powerful, low-level blocks that enable us to bill in any way we want.
Unfortunately, this makes integration pretty painful. Theo Browne summarises the problem best:
IMO, the biggest issue with Stripe is the "split brain" it inherently introduces to your code base. When a customer checks out, the "state of the purchase" is in Stripe. You're then expected to track the purchase in your own database via webhooks.
There are over 258 event types. They all have different amounts of data. The order you get them is not guaranteed. None of them should be trusted. It's far too easy to have a payment be failed in stripe and "subscribed" in your app.
Overall Flow
Here's the easiest way of going about it, making use of the functions in his GitHub repo. The overall flow is:
User clicks "Subscribe" button on frontend, triggering backend endpoint to generate Stripe checkout
Backend creates Stripe customer, stores customerId/userId mapping in database
Backend creates checkout session, returns it to frontend
User completes payment, gets redirected to /success page
/success page triggers backend to sync Stripe data for that customer
Backend fetches customerId from database (referred to as key-value/KV store), and syncs latest data from Stripe API using
syncStripeDataToKV
After sync, frontend redirects user to final destination
On all relevant Stripe webhook events, sync again via
syncStripeDataToKV
Customer Checkout
Authenticate user and get their ID
Check database for existing Stripe customer ID for this user
If no customer ID found, create a new Stripe customer and store the ID in the database, mapped to the user ID
Create a Stripe Checkout session using the customer ID
Return the session data to the frontend
Sync Stripe Data
This is the function that will be used to sync Stripe subscription status with your application. We'll use it in the next step when we're processing webhook events.
Fetch the latest subscription data for the given customer ID from Stripe's API
If no subscriptions found, store an empty state object in the database
If subscriptions found, extract the relevant fields (subscription ID, status, price ID, billing period, payment method details)
Store the subscription data object in the database, keyed by the customer ID
Return the subscription data
Listening to webhook events
Define a list of relevant subscription-related event types to handle
When a webhook is received, call this function to check if the received event type is in the list of relevant events
If so, extract the customer ID from the webhook payload
Call the
syncStripeDataToKV
function to update the customer's subscription data in the database
/success
endpoint
While this isn't 'necessary', there's a good chance your user will make it back to your site before the webhooks do. It's a nasty race condition to handle. Eagerly calling syncStripeDataToKV
will prevent any weird states you might otherwise end up in.
This doesn't solve everything…
Maintaining billing is hard. This guide only applies to simple subscriptions and there are still some things you have to deal with:
Managing STRIPE_SECRET_KEY
and STRIPE_PUBLISHABLE_KEY
env vars for both testing and production
Managing
STRIPE_PRICE_ID
s for all subscription tiers for dev and prod (I can't believe this is still a thing)Exposing sub data from your KV to your user (a dumb endpoint is probably fine)
Tracking "usage" (i.e. a user gets 100 messages per month)
Managing "free trials" ...the list goes on
Making this into 1 line of code
Transparently, we're plugging this article because we've built a system to abstract this complexity away. With Autumn, you can define any pricing model you want (subscriptions, usage-based, credits, add-ons etc) and handle all the logic with one line of code.
Autumn manages all the subscription states. Just make an API call to Autumn to find out whether a user can access a feature. We'll take care of the rest so you can spend more time building what matters.
Give Autumn a try! And let us know what you think hey@useautumn.com