mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-07-28 13:52:17 +02:00
add lemon squeezy as payment provider (#246)
* add lemon squeezy checkout and webhook * add lemonSqueezy customer portal url * Update AccountPage.tsx * add lemon squeezy total revenue function * update app diff * update app diff * add LS docs * Update PricingPage.tsx * add unified payment processor * unify customer portal url * Update paymentProcessor.ts * update paymentProcessor logic * update app diff to use both payments processors * Update contentSections.ts.diff * finishing touches * Update e2e-tests.yml * remove lemonsqueezy from app diff * Update webhook.ts
This commit is contained in:
@@ -61,8 +61,7 @@ export default defineConfig({
|
||||
items: [
|
||||
{ label: 'Authentication', link: '/guides/authentication/' },
|
||||
{ label: 'Authorization', link: '/guides/authorization/' },
|
||||
{ label: 'Stripe Integration', link: '/guides/stripe-integration/' },
|
||||
{ label: 'Stripe Testing', link: '/guides/stripe-testing/' },
|
||||
{ label: 'Payments Integration', link: '/guides/payments-integration/' },
|
||||
{ label: 'Analytics', link: '/guides/analytics/' },
|
||||
{ label: 'SEO', link: '/guides/seo/' },
|
||||
{ label: 'Email Sending', link: '/guides/email-sending/' },
|
||||
|
BIN
opensaas-sh/blog/public/lemon-squeezy/add-product.png
Normal file
BIN
opensaas-sh/blog/public/lemon-squeezy/add-product.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 730 KiB |
BIN
opensaas-sh/blog/public/lemon-squeezy/add-variant.png
Normal file
BIN
opensaas-sh/blog/public/lemon-squeezy/add-variant.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
BIN
opensaas-sh/blog/public/lemon-squeezy/ngrok.png
Normal file
BIN
opensaas-sh/blog/public/lemon-squeezy/ngrok.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
Binary file not shown.
After Width: | Height: | Size: 828 KiB |
BIN
opensaas-sh/blog/public/lemon-squeezy/variant-id.png
Normal file
BIN
opensaas-sh/blog/public/lemon-squeezy/variant-id.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 530 KiB |
@@ -7,7 +7,7 @@ banner:
|
||||
|
||||
Setting up your app's authentication is easy with Wasp. In fact, it's already set up for you in the `main.wasp` file:
|
||||
|
||||
```tsx title="main.wasp" "
|
||||
```tsx title="main.wasp"
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
@@ -33,7 +33,7 @@ Since it needs to send emails to verify users and reset passwords, it requires a
|
||||
To make it easy for you to get started, Open SaaS initially comes with the `Dummy` "email sender" provider, which does not send any emails, but instead logs all email verification links/tokens to the server's console!
|
||||
You can then follow these links to verify the user and continue with the sign-up process.
|
||||
|
||||
```tsx title="main.wasp"
|
||||
```tsx title="main.wasp"
|
||||
emailSender: {
|
||||
provider: Dummy, // logs all email verification links/tokens to the server's console
|
||||
defaultFrom: {
|
||||
|
@@ -20,12 +20,8 @@ If you're looking to deploy your Astro Blog, you can follow the [Deploying your
|
||||
Make sure you've got all your API keys and environment variables set up before you deploy.
|
||||
|
||||
#### Env Vars
|
||||
##### Stripe Vars
|
||||
In the [Stripe integration guide](/guides/stripe-integration), you set up your Stripe API keys using test keys and product ids. You'll need to get the live/production versions of those keys at [https://dashboard.stripe.com](https://dashboard.stripe.com). To get these, repeat the instructions in the [Stripe Integration Guide](/guides/stripe-integration) without being in test mode.
|
||||
- [ ] `STRIPE_KEY`
|
||||
- [ ] `STRIPE_WEBHOOK_SECRET`
|
||||
- [ ] all `STRIPE_..._PRICE_ID` variables
|
||||
- [ ] `REACT_APP_STRIPE_CUSTOMER_PORTAL` (for the client-side)
|
||||
##### Payment Processor Vars
|
||||
In the [Payments Processor integration guide](/guides/payments-integration), you set up your API keys using test keys and test product ids. You'll need to get the live/production versions of those keys. To get these, repeat the instructions in the [Integration Guide](/guides/payments-integration) without being in test mode. Add the new keys to your deployed environment secrets.
|
||||
|
||||
##### Other Vars
|
||||
Many of your other environment variables will probably be the same as in development, but you should double-check that they are set correctly for production.
|
||||
@@ -119,8 +115,8 @@ When you create your Stripe account, Stripe will automatically assign you to the
|
||||
Because this template was built with a specific version of the Stripe API in mind, it could be that your Stripe account is set to a different API version.
|
||||
|
||||
:::note
|
||||
```ts title="stripeClient.ts"
|
||||
export const stripe = new Stripe(process.env.STRIPE_KEY!, {
|
||||
```ts title="stripeClient.ts"
|
||||
export const stripe = new Stripe(process.env.STRIPE_API_KEY!, {
|
||||
apiVersion: 'YYYY-MM-DD', // e.g. 2023-08-16
|
||||
});
|
||||
```
|
||||
@@ -132,7 +128,7 @@ This is why it's important to make sure your Stripe client version also matches
|
||||
To make sure your app is consistent with your Stripe account, here are some steps you can follow:
|
||||
|
||||
1. You can find your `default` API version in the Stripe dashboard under the [Developers](https://dashboard.stripe.com/developers) section.
|
||||
2. Check that the API version in your `stripe/stripeClient.ts` file matches the default API version in your dashboard:
|
||||
2. Check that the API version in your `/src/payment/stripe/stripeClient.ts` file matches the default API version in your dashboard:
|
||||
```ts title="stripeClient.ts" {2}
|
||||
export const stripe = new Stripe(process.env.STRIPE_KEY!, {
|
||||
apiVersion: 'YYYY-MM-DD', // e.g. 2023-08-16
|
||||
@@ -154,7 +150,7 @@ export const stripe = new Stripe(process.env.STRIPE_KEY!, {
|
||||
#### Creating Your Production Webhook
|
||||
1. go to [https://dashboard.stripe.com/webhooks](https://dashboard.stripe.com/webhooks)
|
||||
2. click on `+ add endpoint`
|
||||
3. enter your endpoint url, which will be the url of your deployed server + `/stripe-webhook`, e.g. `https://open-saas-wasp-sh-server.fly.dev/stripe-webhook`
|
||||
3. enter your endpoint url, which will be the url of your deployed server + `/payments-webhook`, e.g. `https://open-saas-wasp-sh-server.fly.dev/payments-webhook`
|
||||

|
||||
4. select the events you want to listen to. These should be the same events you're consuming in your webhook. For example, if you haven't added any additional events to the webhook and are using the defaults that came with this template, then you'll need to add:
|
||||
<br/>- `account.updated`
|
||||
|
277
opensaas-sh/blog/src/content/docs/guides/payments-integration.md
Normal file
277
opensaas-sh/blog/src/content/docs/guides/payments-integration.md
Normal file
@@ -0,0 +1,277 @@
|
||||
---
|
||||
title: Payments Integration
|
||||
banner:
|
||||
content: |
|
||||
Open SaaS is now running on <a href='https://wasp-lang.dev'>Wasp v0.14</a>! <br/>🐝🚀<br/>If you're running an older version, please follow the <a href="https://wasp-lang.dev/docs/migrate-from-0-13-to-0-14">migration instructions.</a>
|
||||
---
|
||||
|
||||
This guide will show you how to set up Payments for testing and local development with the following payment processors:
|
||||
- Stripe
|
||||
- Lemon Squeezy
|
||||
|
||||
:::note[Which should I choose?]
|
||||
Stripe is the industry standard, is more configurable, and has cheaper fees.
|
||||
Lemon Squeezy acts a [Merchant of Record](https://www.lemonsqueezy.com/reporting/merchant-of-record). This means they take care of paying taxes in multiple countries for you, but charge higher fees per transaction.
|
||||
:::
|
||||
|
||||
# Important First Steps
|
||||
|
||||
First, go to `/src/payment/paymentProcessor.ts` and choose which payment processor you'd like to use, e.g. Stripe or Lemon Squeezy:
|
||||
|
||||
```ts title="src/payment/paymentProcessor.ts" ins={5, 7}
|
||||
import { stripePaymentProcessor } from './stripe/paymentProcessor';
|
||||
import { lemonSqueezyPaymentProcessor } from './lemonSqueezy/paymentProcessor';
|
||||
//...
|
||||
|
||||
export const paymentProcessor: PaymentProcessor = stripePaymentProcessor;
|
||||
// or...
|
||||
export const paymentProcessor: PaymentProcessor = lemonSqueezyPaymentProcessor;
|
||||
```
|
||||
|
||||
At this point, you can delete:
|
||||
- the unused payment processor code within the `/src/payment/<unused-provider>` directory,
|
||||
- any unused environment variables from `.env.server` (they will be prefixed with the name of the provider your are not using):
|
||||
- e.g. `STRIPE_API_KEY`, `STRIPE_CUSTOMER_PORTAL_URL`, `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_WEBHOOK_SECRET`
|
||||
- Make sure to also uninstall the unused dependencies:
|
||||
- `npm uninstall @lemonsqueezy/lemonsqueezy.js`
|
||||
- or
|
||||
- `npm uninstall stripe`
|
||||
- Remove any unused fields from the `User` model in the `schema.prisma` file if they exist:
|
||||
- e.g. `lemonSqueezyCustomerPortalUrl`
|
||||
|
||||
Now your code is ready to go with your preferred payment processor and it's time to configure your payment processor's API keys, products, and other settings.
|
||||
|
||||
# Stripe
|
||||
|
||||
First, you'll need to create a Stripe account. You can do that [here](https://dashboard.stripe.com/register).
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
|
||||
If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
|
||||
:::
|
||||
|
||||
## Get your test Stripe API Keys
|
||||
|
||||
Once you've created your account, you'll need to get your test API keys. You can do that by navigating to [https://dashboard.stripe.com/test/apikeys](https://dashboard.stripe.com/test/apikeys) or by going to the [Stripe Dashboard](https://dashboard.stripe.com/test/dashboard) and clicking on the `Developers`.
|
||||
|
||||

|
||||
|
||||
- Click on the `Reveal test key token` button and copy the `Secret key`.
|
||||
- Paste it in your `.env.server` file under `STRIPE_API_KEY=`
|
||||
|
||||
## Create Test Products
|
||||
|
||||
To create a test product, go to the test products url [https://dashboard.stripe.com/test/products](https://dashboard.stripe.com/test/products), or after navigating to your dashboard, click the `test mode` toggle.
|
||||
|
||||

|
||||
|
||||
- Click on the `Add a product` button and fill in the relevant information for your product.
|
||||
- Make sure you select `Software as a service (SaaS)` as the product type.
|
||||
- For Subscription products, make sure you select `Recurring` as the billing type.
|
||||
- For One-time payment products, make sure you select `One-time` as the billing type.
|
||||
- If you want to add different price tiers for the same product, click the `Add another price` button at the buttom.
|
||||
|
||||

|
||||
|
||||
- After you save the product, you'll be directed to the product page.
|
||||
- Copy the price IDs and paste them in the `.env.server` file
|
||||
- We've set you up with two example subscription product environment variables, `PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=` and `PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=`.
|
||||
- As well as a one-time payment product/credits-based environment variable, `PAYMENTS_CREDITS_10_PLAN_ID=`.
|
||||
- Note that if you change the names of the price IDs, you'll need to update your server code to match these names as well
|
||||
|
||||
## Create a Test Customer
|
||||
|
||||
To create a test customer, go to the test customers url [https://dashboard.stripe.com/test/customers](https://dashboard.stripe.com/test/customers).
|
||||
|
||||
- Click on the `Add a customer` button and fill in the relevant information for your test customer.
|
||||
:::note
|
||||
When filling in the test customer email address, use an address you have access to and will use when logging into your SaaS app. This is important because the email address is used to identify the customer when creating a subscription and allows you to manage your test user's payments/subscriptions via the test customer portal
|
||||
:::
|
||||
|
||||
## Get your Customer Portal Link
|
||||
|
||||
Go to https://dashboard.stripe.com/test/settings/billing/portal in the Stripe Dashboard and activate and copy the `Customer portal link`. Paste it in your `.env.server` file:
|
||||
|
||||
```ts title=".env.server"
|
||||
STRIPE_CUSTOMER_PORTAL_URL=<your-test-customer-portal-link>
|
||||
```
|
||||
|
||||
## Install the Stripe CLI
|
||||
|
||||
To install the Stripe CLI with homebrew, run the following command in your terminal:
|
||||
|
||||
```sh
|
||||
brew install stripe/stripe-cli/stripe
|
||||
```
|
||||
|
||||
or for other install scripts or OSes, follow the instructions [here](https://stripe.com/docs/stripe-cli#install).
|
||||
|
||||
Now, let's start the webhook server and get our webhook signing secret.
|
||||
|
||||
First, login:
|
||||
```sh
|
||||
stripe login
|
||||
```
|
||||
|
||||
:::caution[Errors running the Stripe CLI]
|
||||
If you're seeing errors, consider appending `sudo` to the stripe commands.
|
||||
See this [GitHuh issue](https://github.com/stripe/stripe-cli/issues/933) for more details.
|
||||
:::
|
||||
|
||||
```sh
|
||||
stripe listen --forward-to localhost:3001/payments-webhook
|
||||
```
|
||||
|
||||
You should see a message like this:
|
||||
|
||||
```sh
|
||||
> Ready! You are using Stripe API Version [2023-08-16]. Your webhook signing secret is whsec_8a... (^C to quit)
|
||||
```
|
||||
|
||||
copy this secret to your `.env.server` file under `STRIPE_WEBHOOK_SECRET=`.
|
||||
|
||||
## Testing Webhooks via the Stripe CLI
|
||||
|
||||
- In a new terminal window, run the following command:
|
||||
|
||||
```sh
|
||||
stripe login
|
||||
```
|
||||
|
||||
- start the Stripe CLI webhook forwarding on port 3001 where your Node server is running.
|
||||
|
||||
```sh
|
||||
stripe listen --forward-to localhost:3001/payments-webhook
|
||||
```
|
||||
|
||||
remember to copy and paste the outputted webhook signing secret (`whsec_...`) into your `.env.server` file under `STRIPE_WEBHOOK_SECRET=` if you haven't already.
|
||||
|
||||
- In another terminal window, trigger a test event:
|
||||
|
||||
```sh
|
||||
stripe trigger payment_intent.succeeded
|
||||
```
|
||||
|
||||
The results of the event firing will be visible in the initial terminal window. You should see messages like this:
|
||||
|
||||
```sh
|
||||
...
|
||||
2023-11-21 09:31:09 --> invoice.paid [evt_1OEpMPILOQf67J5TjrUgRpk4]
|
||||
2023-11-21 09:31:09 <-- [200] POST http://localhost:3001/payments-webhook [evt_1OEpMPILOQf67J5TjrUgRpk4]
|
||||
2023-11-21 09:31:10 --> invoice.payment_succeeded [evt_1OEpMPILOQf67J5T3MFBr1bq]
|
||||
2023-11-21 09:31:10 <-- [200] POST http://localhost:3001/payments-webhook [evt_1OEpMPILOQf67J5T3MFBr1bq]
|
||||
2023-11-21 09:31:10 --> checkout.session.completed [evt_1OEpMQILOQf67J5ThTZ0999r]
|
||||
2023-11-21 09:31:11 <-- [200] POST http://localhost:3001/payments-webhook [evt_1OEpMQILOQf67J5ThTZ0999r]
|
||||
```
|
||||
|
||||
For more info on testing webhooks, check out https://stripe.com/docs/webhooks#test-webhook
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
|
||||
If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
|
||||
:::
|
||||
|
||||
## Testing Checkout and Payments via the Client
|
||||
|
||||
Make sure the **Stripe CLI is running** by following the steps above.
|
||||
You can then test the payment flow via the client by doing the following:
|
||||
|
||||
- Click on a Buy button on the for any of the products on the homepage. You should be redirected to the checkout page.
|
||||
- Fill in the form with the following test credit card number `4242 4242 4242 4242` and any future date for the expiration date and any 3 digits for the CVC.
|
||||
|
||||
- Click on the "Pay" button. You should be redirected to the success page.
|
||||
|
||||
- Check your terminal window for status messages and logs
|
||||
|
||||
- You can also check your Database via the DB Studio to see if the user entity has been updated by running:
|
||||
|
||||
```sh
|
||||
wasp db studio
|
||||
```
|
||||
|
||||

|
||||
|
||||
- Navigate to `localhost:5555` and click on the `users` table. You should see the `subscriptionStatus` is `active` for the user that just made the purchase.
|
||||
|
||||
:::note
|
||||
If you want to learn more about how a user's payment status, subscription status, and subscription tier affect a user's priveledges within the app, check out the [User Overview](/general/user-overview) reference.
|
||||
:::
|
||||
|
||||
# Lemon Squeezy
|
||||
|
||||
First, make sure you've defined your payment processor in `src/payment/paymentProcessor.ts`, as described in the [important first steps](#important-first-steps).
|
||||
|
||||
Next, you'll need to create a Lemon Squeezy account in test mode. You can do that [here](https://lemonsqueezy.com).
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
|
||||
If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
|
||||
:::
|
||||
|
||||
## Get your test Lemon Squeezy API Keys
|
||||
|
||||
Once you've created your account, you'll need to get your test API keys. You can do that by navigating to [https://app.lemonsqueezy.com/settings/api](https://app.lemonsqueezy.com/settings/api) and creating a new API key.
|
||||
|
||||
- Click on the `+` button
|
||||
- Give your API key a name
|
||||
- Copy and paste it in your `.env.server` file under `LEMONSQUEEZY_API_KEY=`
|
||||
|
||||
## Create Test Products
|
||||
|
||||
To create a test product, go to the test products url [https://app.lemonsqueezy.com/products](https://app.lemonsqueezy.com/products).
|
||||
|
||||
- Click on the `+ New Product` button and fill in the relevant information for your product.
|
||||
- Fill in the general information.
|
||||
- For pricing, select the type of product you'd like to create, e.g. `Subscription` for a recurring monthly payment product or `Single Payment` for credits-based product.
|
||||

|
||||
- Make sure you select `Software as a service (SaaS)` as the Tax category type.
|
||||
- If you want to add different price tiers for `Subscription` products, click on `add variant` under the `variants` tab. Here you can input the name of the variant (e.g. "Hobby", "Pro"), and that variant's price.
|
||||

|
||||
- For a product with no variants, on the product page, click the `...` menu button and select `Copy variant ID`
|
||||

|
||||
- For a product with variants, on the product page, click on the product, go to the variants tab and select `Copy ID` for each variant.
|
||||

|
||||
- Paste these IDs in the `.env.server` file:
|
||||
- We've set you up with two example subscription product environment variables, `PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=` and `PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=`.
|
||||
- As well as a one-time payment product/credits-based environment variable, `PAYMENTS_CREDITS__10_PLAN_ID=`.
|
||||
- Note that if you change the names of the these environment variables, you'll need to update your app code to match these names as well.
|
||||
|
||||
## Create and Use the Lemon Squeezy Webhook in Local Development
|
||||
|
||||
Lemon Squeezy sends messages/updates to your Wasp app via its webhook, e.g. when a payment is successful. For that to work during development, we need to expose our locally running (via `wasp start`) Wasp app and make it available online, specifically the server part of it. Since the Wasp server runs on port 3001, you should run ngrok on port 3001, which will provide you with a public URL that you can use to configure Lemon Squeezy with.
|
||||
|
||||
To do this, first make sure you have installed [ngrok](https://ngrok.com/docs/getting-started/).
|
||||
|
||||
Once installed, and with your wasp app running, run:
|
||||
```sh
|
||||
ngrok http 3001
|
||||
```
|
||||
|
||||

|
||||
|
||||
Ngrok will output a forwarding address for you. Copy and paste this address and add `/payments-webhook` to the end (this URL path has been configured for you already in `main.wasp` under the `api paymentsWebhook` definition). It should look something like this:
|
||||
|
||||
```sh title="Callback URL"
|
||||
https://89e5-2003-c7-153c-72a5-f837.ngrok-free.app/payments-webhook
|
||||
```
|
||||
|
||||
Now go to your [Lemon Squeezy Webhooks Dashboard](https://app.lemonsqueezy.com/settings/webhooks):
|
||||
- click the `+` button.
|
||||
- add the newly created webhook forwarding url to the `Callback URL` section.
|
||||
- give your webhook a signing secret (a long, random string).
|
||||
- copy and paste this same signing secret into your `.env.server` file under `LEMONSQUEEZY_WEBHOOK_SECRET=`
|
||||
- make sure to select at least the following updates to be sent:
|
||||
- order_created
|
||||
- subscription_created
|
||||
- subscription_updated
|
||||
- subscription_cancelled
|
||||
- click `save`
|
||||
|
||||
You're now ready to start consuming Lemon Squeezy webhook events in local development.
|
||||
|
||||
# Deploying
|
||||
|
||||
Once you deploy your app, you can follow the same steps, just make sure that you are no longer in test mode within the Stripe or Lemon Squeezy Dashboards. After you've repeated the steps in live mode, add the new API keys and price/variant IDs to your environment variables in your deployed environment.
|
@@ -1,117 +0,0 @@
|
||||
---
|
||||
title: Stripe Integration
|
||||
banner:
|
||||
content: |
|
||||
Open SaaS is now running on <a href='https://wasp-lang.dev'>Wasp v0.14</a>! <br/>🐝🚀<br/>If you're running an older version, please follow the <a href="https://wasp-lang.dev/docs/migrate-from-0-13-to-0-14">migration instructions.</a>
|
||||
---
|
||||
|
||||
This guide will show you how to set up your Stripe account for testing and local development.
|
||||
|
||||
Once you deploy your app, you can follow the same steps, just make sure you're using your live Stripe API keys and product IDs and you are no longer in test mode within the Stripe Dashboard.
|
||||
|
||||
To get started, you'll need to create a Stripe account. You can do that [here](https://dashboard.stripe.com/register).
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
|
||||
If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
|
||||
:::
|
||||
|
||||
## Get your test Stripe API Keys
|
||||
|
||||
Once you've created your account, you'll need to get your test API keys. You can do that by navigating to [https://dashboard.stripe.com/test/apikeys](https://dashboard.stripe.com/test/apikeys) or by going to the [Stripe Dashboard](https://dashboard.stripe.com/test/dashboard) and clicking on the `Developers`.
|
||||
|
||||

|
||||
|
||||
- Click on the `Reveal test key token` button and copy the `Secret key`.
|
||||
- Paste it in your `.env.server` file under `STRIPE_KEY=`
|
||||
|
||||
## Create Test Products
|
||||
|
||||
To create a test product, go to the test products url [https://dashboard.stripe.com/test/products](https://dashboard.stripe.com/test/products), or after navigating to your dashboard, click the `test mode` toggle.
|
||||
|
||||

|
||||
|
||||
- Click on the `Add a product` button and fill in the relevant information for your product.
|
||||
- Make sure you select `Software as a service (SaaS)` as the product type.
|
||||
- For Subscription products, make sure you select `Recurring` as the billing type.
|
||||
- For One-time payment products, make sure you select `One-time` as the billing type.
|
||||
- If you want to add different price tiers for the same product, click the `Add another price` button at the buttom.
|
||||
|
||||

|
||||
|
||||
- After you save the product, you'll be directed to the product page.
|
||||
- Copy the price IDs and paste them in the `.env.server` file
|
||||
- We've set you up with two example subscription product environment variables, `STRIPE_HOBBY_SUBSCRIPTION_PRICE_ID=` and `STRIPE_PRO_SUBSCRIPTION_PRICE_ID=`.
|
||||
- As well as a one-time payment product/credits-based environment variable, `STRIPE_CREDITS_PRICE_ID=`.
|
||||
- Note that if you change the names of the price IDs, you'll need to update your server code to match these names as well
|
||||
|
||||
## Create a Test Customer
|
||||
|
||||
To create a test customer, go to the test customers url [https://dashboard.stripe.com/test/customers](https://dashboard.stripe.com/test/customers).
|
||||
|
||||
- Click on the `Add a customer` button and fill in the relevant information for your test customer.
|
||||
:::note
|
||||
When filling in the test customer email address, use an address you have access to and will use when logging into your SaaS app. This is important because the email address is used to identify the customer when creating a subscription and allows you to manage your test user's payments/subscriptions via the test customer portal
|
||||
:::
|
||||
|
||||
## Get your Customer Portal Link
|
||||
|
||||
Go to https://dashboard.stripe.com/test/settings/billing/portal in the Stripe Dashboard and activate and copy the `Customer portal link`. Paste it in your `.env.client` file:
|
||||
|
||||
```ts title=".env.client"
|
||||
REACT_APP_STRIPE_CUSTOMER_PORTAL=<your-test-customer-portal-link>
|
||||
```
|
||||
|
||||
Your Stripe customer portal link is imported into `src/user/AccountPage.tsx` and used to redirect users to the Stripe customer portal when they click the `Manage Subscription` button.
|
||||
|
||||
```tsx title="src/user/AccountPage.tsx" {5} "import.meta.env.REACT_APP_STRIPE_CUSTOMER_PORTAL"
|
||||
function CustomerPortalButton() {
|
||||
const handleClick = () => {
|
||||
try {
|
||||
const schema = z.string().url();
|
||||
const customerPortalUrl = schema.parse(import.meta.env.REACT_APP_STRIPE_CUSTOMER_PORTAL);
|
||||
window.open(customerPortalUrl, '_blank');
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
:::danger[Client-side Environment Variables]
|
||||
Client-side environment variables, unlike server-side environment variables, should never be used to store sensitive information as they are injected at build time and are exposed to the client.
|
||||
:::
|
||||
|
||||
## Install the Stripe CLI
|
||||
|
||||
To install the Stripe CLI with homebrew, run the following command in your terminal:
|
||||
|
||||
```sh
|
||||
brew install stripe/stripe-cli/stripe
|
||||
```
|
||||
|
||||
or for other install scripts or OSes, follow the instructions [here](https://stripe.com/docs/stripe-cli#install).
|
||||
|
||||
Now, let's start the webhook server and get our webhook signing secret.
|
||||
|
||||
First, login:
|
||||
```sh
|
||||
stripe login
|
||||
```
|
||||
|
||||
:::caution[Errors running the Stripe CLI]
|
||||
If you're seeing errors, consider appending `sudo` to the stripe commands.
|
||||
See this [GitHuh issue](https://github.com/stripe/stripe-cli/issues/933) for more details.
|
||||
:::
|
||||
|
||||
```sh
|
||||
stripe listen --forward-to localhost:3001/stripe-webhook
|
||||
```
|
||||
|
||||
You should see a message like this:
|
||||
|
||||
```sh
|
||||
> Ready! You are using Stripe API Version [2023-08-16]. Your webhook signing secret is whsec_8a... (^C to quit)
|
||||
```
|
||||
|
||||
copy this secret to your `.env.server` file under `STRIPE_WEBHOOK_SECRET=`.
|
@@ -1,77 +0,0 @@
|
||||
---
|
||||
title: Stripe Testing
|
||||
banner:
|
||||
content: |
|
||||
Open SaaS is now running on <a href='https://wasp-lang.dev'>Wasp v0.14</a>! <br/>🐝🚀<br/>If you're running an older version, please follow the <a href="https://wasp-lang.dev/docs/migrate-from-0-13-to-0-14">migration instructions.</a>
|
||||
---
|
||||
This guide will show you how to test and try out your checkout, payments, and webhooks locally.
|
||||
|
||||
First, make sure you've set up your Stripe account for local development. You can find the guide [here](/guides/stripe-integration).
|
||||
|
||||
## Testing Webhooks via the Stripe CLI
|
||||
|
||||
- In a new terminal window, run the following command:
|
||||
|
||||
```sh
|
||||
stripe login
|
||||
```
|
||||
|
||||
- start the Stripe CLI webhook forwarding on port 3001 where your Node server is running.
|
||||
|
||||
```sh
|
||||
stripe listen --forward-to localhost:3001/stripe-webhook
|
||||
```
|
||||
|
||||
remember to copy and paste the outputted webhook signing secret (`whsec_...`) into your `.env.server` file under `STRIPE_WEBHOOK_SECRET=` if you haven't already.
|
||||
|
||||
- In another terminal window, trigger a test event:
|
||||
|
||||
```sh
|
||||
stripe trigger payment_intent.succeeded
|
||||
```
|
||||
|
||||
The results of the event firing will be visible in the initial terminal window. You should see messages like this:
|
||||
|
||||
```sh
|
||||
...
|
||||
2023-11-21 09:31:09 --> invoice.paid [evt_1OEpMPILOQf67J5TjrUgRpk4]
|
||||
2023-11-21 09:31:09 <-- [200] POST http://localhost:3001/stripe-webhook [evt_1OEpMPILOQf67J5TjrUgRpk4]
|
||||
2023-11-21 09:31:10 --> invoice.payment_succeeded [evt_1OEpMPILOQf67J5T3MFBr1bq]
|
||||
2023-11-21 09:31:10 <-- [200] POST http://localhost:3001/stripe-webhook [evt_1OEpMPILOQf67J5T3MFBr1bq]
|
||||
2023-11-21 09:31:10 --> checkout.session.completed [evt_1OEpMQILOQf67J5ThTZ0999r]
|
||||
2023-11-21 09:31:11 <-- [200] POST http://localhost:3001/stripe-webhook [evt_1OEpMQILOQf67J5ThTZ0999r]
|
||||
```
|
||||
|
||||
For more info on testing webhooks, check out https://stripe.com/docs/webhooks#test-webhook
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
|
||||
If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
|
||||
:::
|
||||
|
||||
## Testing Checkout and Payments via the Client
|
||||
|
||||
Make sure the **Stripe CLI is running** by following the steps above.
|
||||
You can then test the payment flow via the client by doing the following:
|
||||
|
||||
- Click on a Buy button on the for any of the products on the homepage. You should be redirected to the checkout page.
|
||||
- Fill in the form with the following test credit card number `4242 4242 4242 4242` and any future date for the expiration date and any 3 digits for the CVC.
|
||||
|
||||
- Click on the "Pay" button. You should be redirected to the success page.
|
||||
|
||||
- Check your terminal window for status messages and logs
|
||||
|
||||
- You can also check your Database via the DB Studio to see if the user entity has been updated by running:
|
||||
|
||||
```sh
|
||||
wasp db studio
|
||||
```
|
||||
|
||||

|
||||
|
||||
- Navigate to `localhost:5555` and click on the `users` table. You should see the `subscriptionStatus` is `active` for the user that just made the purchase.
|
||||
|
||||
:::note
|
||||
If you want to learn more about how a user's payment status, subscription status, and subscription tier affect a user's priveledges within the app, check out the [User Overview](/general/user-overview) reference.
|
||||
:::
|
@@ -172,7 +172,7 @@ Next, copy the `.env.server.example` file to `.env.server`.
|
||||
cp .env.server.example .env.server
|
||||
```
|
||||
|
||||
`.env.server` is where API keys for services like Stripe, email sender, and similar go, and this is where you will want to put them in later.
|
||||
`.env.server` is where API keys for services like payments, email sender, and similar go, and this is where you will want to put them in later.
|
||||
For now, you can leave it as it is (dummy API keys), this will be enough to run the app.
|
||||
|
||||
Then run:
|
||||
|
@@ -22,8 +22,8 @@ Awesome, you now have your very own SaaS app up and running! But, first, here ar
|
||||
[ Server ] <a href="http://localhost:3000/email-verification?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InZpbm55QHdhc3Auc2giLCJleHAiOjE3MTg5NjUyNTB9.PkRGrmuDPuYFXkTprf7QpAye0e_O9a70xbER6LfxGJw">Verify email</a>
|
||||
[ Server ] ════════════════════════
|
||||
```
|
||||
2. Your app is still missing some key configurations (e.g. API keys for Stripe, OpenAI, AWS S3, Auth, Analytics). These services won't work at the moment, but don't fear, because **we've provided detailed guides in these docs to help you set up all the services in this template**.
|
||||
3. If you want to get a feel for what your SaaS could look like when finished, **check out [OpenSaaS.sh](https://opensaas.sh) in your browser. It was built using this template!** So make sure to log in, play around with the demo app, make a test Stripe payment, and check out the admin dashboard.
|
||||
2. Your app is still missing some key configurations (e.g. API keys for Payment Processors, OpenAI, AWS S3, Auth, Analytics). These services won't work at the moment, but don't fear, because **we've provided detailed guides in these docs to help you set up all the services in this template**.
|
||||
3. If you want to get a feel for what your SaaS could look like when finished, **check out [OpenSaaS.sh](https://opensaas.sh) in your browser. It was built using this template!** So make sure to log in, play around with the demo app, make a test payment, and check out the admin dashboard.
|
||||
|
||||
In the sections below, we will take a short guide through the codebase and the app's main features. Then at the end of this tour, we also prepared a checklist of likely changes you will want to make to the app to make it your own.
|
||||
|
||||
@@ -71,7 +71,7 @@ If you are using an older version of the OpenSaaS template with Wasp `v0.13.x` o
|
||||
│ ├── landing-page # Landing page related code
|
||||
│ ├── messages # Logic for app user messages.
|
||||
│ ├── newsletter/ # Logic for scheduled recurring newsletter sending.
|
||||
│ ├── payment/ # Logic for handling Stripe payments and webhooks.
|
||||
│ ├── payment/ # Logic for handling payments and webhooks.
|
||||
│ ├── server/ # Scripts, shared server utils, and other server-specific code (NodeJS).
|
||||
│ ├── shared/ # Shared constants and util functions.
|
||||
│ └── user/ # Logic related to users and their accounts.
|
||||
@@ -187,57 +187,59 @@ For development purposes, Wasp provides a `Dummy` email sender which Open SaaS c
|
||||
|
||||
We will explain more about these auth methods, and how to properly integrate them into your app, in the [Authentication Guide](/guides/authentication).
|
||||
|
||||
### Subscription Payments with Stripe
|
||||
### Subscription Payments with Stripe or Lemon Squeezy
|
||||
|
||||
No SaaS is complete without payments, specifically subscription payments. That's why this template comes with a fully functional Stripe integration.
|
||||
No SaaS is complete without payments, specifically subscription payments. That's why this template comes with a fully functional Stripe or Lemon Squeezy integration.
|
||||
|
||||
Let's take a quick look at how payments are handled in this template.
|
||||
|
||||
1. a user clicks the `BUY` button and a **Stripe Checkout session** is created on the server
|
||||
2. the user is redirected to the Stripe Checkout page where they enter their payment info
|
||||
3. the user is redirected back to the app and the Stripe Checkout session is completed
|
||||
4. Stripe sends a webhook event to the server with the payment info
|
||||
1. a user clicks the `BUY` button and a **Checkout session** is created on the server
|
||||
2. the user is redirected to the Checkout page where they enter their payment info
|
||||
3. the user is redirected back to the app and the Checkout session is completed
|
||||
4. Stripe / Lemon Squeezy sends a webhook event to the server with the payment info
|
||||
5. The app server's **webhook handler** handles the event and updates the user's subscription status
|
||||
|
||||
The logic for creating the Stripe Checkout session is defined in the `src/payment/operation.ts` file. [Actions](https://wasp-lang.dev/docs/data-model/operations/actions) are a type of Wasp Operation, specifically your server-side functions that are used to **write** or **update** data to the database. Once they're defined in the `main.wasp` file, you can easily call them on the client-side:
|
||||
The payment processor you choose (Stripe or Lemon Squeezy) and its related functions can be found at `src/payment/paymentProcessor.ts`. The `Payment Processor` object holds the logic for creating checkout sessions, webhooks, etc.
|
||||
|
||||
The logic for creating the Checkout session is defined in the `src/payment/operation.ts` file. [Actions](https://wasp-lang.dev/docs/data-model/operations/actions) are a type of Wasp Operation, specifically your server-side functions that are used to **write** or **update** data to the database. Once they're defined in the `main.wasp` file, you can easily call them on the client-side:
|
||||
|
||||
a) define the action in the `main.wasp` file
|
||||
```js title="main.wasp"
|
||||
action generateStripeCheckoutSession {
|
||||
fn: import { generateStripeCheckoutSession } from "@src/payment/operations",
|
||||
action generateCheckoutSession {
|
||||
fn: import { generateCheckoutSession } from "@src/payment/operations",
|
||||
entities: [User]
|
||||
}
|
||||
```
|
||||
|
||||
b) implement the action in the `src/payment/operations` file
|
||||
```js title="src/server/actions.ts"
|
||||
export const generateStripeCheckoutSession = async (paymentPlanId, context) => {
|
||||
export const generateCheckoutSession = async (paymentPlanId, context) => {
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
c) call the action on the client-side
|
||||
```js title="src/client/app/SubscriptionPage.tsx"
|
||||
import { generateStripeCheckoutSession } from "wasp/client/operations";
|
||||
import { generateCheckoutSession } from "wasp/client/operations";
|
||||
|
||||
const handleBuyClick = async (paymentPlanId) => {
|
||||
const stripeCheckoutSession = await generateStripeCheckoutSession(paymentPlanId);
|
||||
const checkoutSession = await generateCheckoutSession(paymentPlanId);
|
||||
};
|
||||
```
|
||||
|
||||
The webhook handler is defined in the `src/payment/stripe/webhook.ts` file. Unlike Actions and Queries in Wasp which are only to be used internally, we define the webhook handler in the `main.wasp` file as an API endpoint in order to expose it externally to Stripe
|
||||
The webhook handler is defined in the `src/payment/webhook.ts` file. Unlike Actions and Queries in Wasp which are only to be used internally, we define the webhook handler in the `main.wasp` file as an API endpoint in order to expose it externally to Stripe
|
||||
|
||||
```js title="main.wasp"
|
||||
api stripeWebhook {
|
||||
fn: import { stripeWebhook } from "@src/payment/stripe/webhook",
|
||||
httpRoute: (POST, "/stripe-webhook")
|
||||
api paymentsWebhook {
|
||||
fn: import { paymentsWebhook } from "@src/payment/webhook",
|
||||
httpRoute: (POST, "/payments-webhook")
|
||||
entities: [User],
|
||||
}
|
||||
```
|
||||
|
||||
Within the webhook handler, we look for specific events that Stripe sends us to let us know which payment was completed and for which user. Then we update the user's subscription status in the database.
|
||||
Within the webhook handler, we look for specific events that the Payment Processor sends us to let us know which payment was completed and for which user. Then we update the user's subscription status in the database.
|
||||
|
||||
To learn more about configuring the app to handle your products and payments, check out the [Stripe Integration guide](/guides/stripe-integration).
|
||||
To learn more about configuring the app to handle your products and payments, check out the [Payments Integration guide](/guides/payments-integration).
|
||||
|
||||
:::tip[Star our Repo on GitHub! 🌟]
|
||||
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!
|
||||
@@ -248,7 +250,7 @@ If you're finding this template and its guides useful, consider giving us [a sta
|
||||
|
||||
### Analytics and Admin Dashboard
|
||||
|
||||
Keeping an eye on your metrics is crucial for any SaaS. That's why we've built an administrator's dashboard where you can view your app's stats, user data, and Stripe revenue all in one place.
|
||||
Keeping an eye on your metrics is crucial for any SaaS. That's why we've built an administrator's dashboard where you can view your app's stats, user data, and revenue all in one place.
|
||||
|
||||
<!-- TODO: add pic of admin dash -->
|
||||
|
||||
@@ -276,7 +278,7 @@ For more info on integrating Plausible or Google Analytics, check out the [Analy
|
||||
When you first start your Open SaaS app straight from the template, it will run, but many of the services won't work because they lack your own API keys. Here are list of services that need your API keys to work properly:
|
||||
|
||||
- Auth Methods (Google, GitHub)
|
||||
- Stripe
|
||||
- Stripe or Lemon Squeezy
|
||||
- OpenAI (Chat GPT API)
|
||||
- Email Sending (Sendgrid) -- you must set this up if you're using the `email` Auth method
|
||||
- Analytics (Plausible or Google Analytics)
|
||||
@@ -345,4 +347,4 @@ But before you start setting up the main features, let's walk through the custom
|
||||
|
||||
## What's next?
|
||||
|
||||
In the following `Guides` sections, we'll walk you through getting those API keys and setting up the finer points of features such as Stripe Payments & Webhooks, Auth, Email Sending, Analytics, and more.
|
||||
In the following `Guides` sections, we'll walk you through getting those API keys and setting up the finer points of features such as Payments & Webhooks, Auth, Email Sending, Analytics, and more.
|
||||
|
Reference in New Issue
Block a user