Lemon Squeezy and Next.js 13: A Detailed Guide to Effortless Payment Integration
Discover how to integrate payments into a Next.js SaaS App using Lemon Squeezy. Our guide covers creating API keys, managing subscriptions, handling webhooks, and storing updates. Learn to build a robust subscription setup with this powerful tech stack.
Dive into the power of Lemon Squeezy as we take a journey through setting up a fully functional SaaS App with subscriptions using Next.js App Directory. In this hands-on tutorial, you'll learn how to create an API key, display products in a pricing table using TailwindUI, and manage subscriptions with Lemon Squeezy.
We'll also cover how to handle Lemon Squeezy webhook events, using zod for input parsing, and how to store subscription updates in a Postgres database using drizzle ORM. Additionally, you'll learn how to synchronize product data between Lemon Squeezy and your own database, and manage user subscriptions using Vercel's server actions.
By the end of this guide, you'll be equipped with the skills to create a robust subscription setup, leveraging Lemon Squeezy's functionalities and a powerful tech stack. Let's get started!
Setting up Lemon Squeezy 🍋
As we walk through this process, ensure you've enabled the test mode - this allows us to experiment freely without the risk of errors.
In order to get started you should have created a store in Lemon Squeezy as well as some products and variants. In this tutorial I will focus on subscriptions, but it should work equally well for other products.
Next, let's generate an API Key at https://app.lemonsqueezy.com/settings/api to connect to our store:
Lemon Squeezy API Key
Add this as an environment variable to your Next.js project:
Creating a Dynamic Pricing Table with Product Info
Now that we've laid the groundwork, our next step involves fetching all the product and variant information via API and presenting it in a pricing table. I am a huge fan of TailwindUI so I picked one of their pricing tables from here. This is what our final pricing table will look like:
Pricing table fetching data from Lemon Squeezy for BacklinkGPT.com
First, we need to fetch all the products with the getProductVariants
function, which also has the createHeaders
and createRequestOptions
utility functions to build out the request:
view rawlemon-squeezy.ts hosted with ❤ by GitHub
Furthermore, with the help of GPT4 I also quickly created a zod
model SLemonSqueezyRequest
and the corresponding type TLemonSqueezyRequest
to help me parsing the API output and enhanced type safety and auto-completion functionality with the data:
view rawzod-lemon-squeezy.ts hosted with ❤ by GitHub
With the function and zod models ready, I created a pricing.tsx
component to fetch all the data, which I then pass to the pricing table. One more important convenience function I created is the createCheckoutLink
function to generate the hosted checkout link.
view rawpricing.tsx hosted with ❤ by GitHub
Finally, I ran into a small problem when I tried to show the variant description with checkmarks in my pricing table:
To do this, I used the JSDOM parser to pull out all the feature elements:
When you're satisfied with your pricing table in the dev environment
, it's easy to move the products from test
mode to live
mode. All you need to do is create a new API key
for the live environment, add it to your environment variables, and you're done with the pricing table! 🥳
Listening to Subscription Webhook Events
Now that the pricing table is ready, we need to know about any new subscription updates in our app to manage access and such. To do this, we can create a Route Handler
. It listens for certain Lemon Squeezy Webhook Requests and saves the data in our database. Then, we can use this info to develop any logic we want.
In the example below, I use zod
for input parsing and drizzle ORM
to create the tables and store everything in my Postgres Neon Database
.
Lemon Squeezy has some excellent documentation on webhooks, and I followed their recommendation of listening to the subscription_created
webhook.
In their documentation they also do a great job in explaining the whole subscription's lifecycle and how and when which event will be fired.
I did not implement the logic for subscription_payment_success since I figured I just tell customers to log into their Lemon Squeezy Account to view the invoices. I might add this though in the future and update the blog post.
Setting up the Route Handler
To be able to receive the Lemon Squeezy webhooks in my Next.js
app directory, I created the new Route Handler under /src/app/api/lemon-squeezy/route.ts
.
Subscribe to continue reading.
Already a reader?