Payments
Accepting payments and setting up a paywall
LemonSqueezy is used to handle payments. It has built-in VAT/sales tax compliance, affiliates & marketing tools.
Set up LemonSqueezy
First, create an LemonSqueezy account or sign in. Create a store & add your digital products. It usually takes 1-2 days for it to get verified.
Once that is ready, we’ll set up the app to handle webhooks from LemonSqueezy:
-
Go to
Settings -> Webhooks
and add a new WebhookAdd a new webhook to LemonSqueezy
-
Fill in Callback URL with
https://yourwebsite.com/api/payments/lemonsqueezy
& select all events. -
Add your defined
LEMON_SQUEEZY_WEBHOOK_SECRET
to your.env
file.Select all events & specify your LEMON_SQUEEZY_WEBHOOK_SECRET
Handling webhooks
Under app/api/payments/lemonsqueezy/route.ts
you’ll find an API route that handles both one-time-payments and subscriptions from LemonSqueezy.
It will do the following:
- Verify if the request is legitimate by matching
LEMON_SQUEEZY_WEBHOOK_SECRET
- Get purchased product, based on the
variant_id
- Match the user email with our
profiles
table- If there is a matching user, it will edit
purchase
column of the matching user in theprofiles
table based on the logic you specify in the webhook. Feel free to add any logic here you’ll use in your app to handle page access. - If no matching user is found, it will simply update the
purchases
table with a new entry
- If there is a matching user, it will edit
Storing webhook data
We’ll store all webhook data coming from LemonSqueezy in our own database as well.
The purchases
table should already exist if you followed the Quick Setup guide and ran the Supabase migrations using the CLI:
If you haven’t done this yet, please go back to the Quick Setup guide first. Alternatively, you can manually create the table by running the SQL from this file in your Supabase SQL editor:
supabase/migrations/20240000000007_purchases.sql
Make sure RLS is turned on. We don’t need to add any rules as we’ll be using the service key for to interact with this table.
Set up paywall
All demo apps include a paywall using a credit system. You can modify the logic in app/api/payments/lemonsqueezy/route.ts
to add more credits after a succesfull purchase.
You can adjust the code to handle access based on the purchase
column having
a specific value. This allows for handling lifetime access systems or
subscriptions.
Logic flow
The codebase includes a credit-based paywall system that uses cached queries for better performance. Here’s how it works:
The paywall logic:
- Check if the demo app is paywalled (specified in
toolConfig.ts
). - Uses cached queries to efficiently verify user credit balance:
- If yes, grant access.
- If no, display the
PaymentModal
component.
The cached queries system helps reduce database load and improve performance compared to direct Supabase queries.