opensaas-sh/blog/src/content/docs/guides/payment-integrations/polar.mdx
import ngrok from '@assets/ngrok.png'; import polarUserTable from '@assets/polar/user-table.png'; import polarWebhookLogs from '@assets/polar/webhook-log.png'; import { Image } from 'astro:assets';
First, make sure you've defined your payment processor in src/payment/paymentProcessor.ts, as described in the important first steps.
Next, you'll need to create a Polar account in the sandbox mode. You can do that here.
:::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 :::
Polar features two separate environments:
They are fully isolated from each other, which means that you need to create seperate organizations for each of them. They also feature independent products, sales, access tokens, etc.
For local development and testing, you'll want to use Polar's sandbox mode.
To enable sandbox mode, make sure that POLAR_SANDBOX_MODE is set to true in your .env.server file:
POLAR_SANDBOX_MODE=true
When you're ready to deploy your app, we'll remind you to set this to false.
Once you've created your account, you'll need to get your organization access token. You can do that by:
Developers section under the Settings > General page.New Token button to create a new token.No expiration is fine for sandbox mode, but discouraged for production mode.checkouts:writecustomer_sessions:writecustomers:readcustomers:writeorders:read.env.server file:
POLAR_ORGANIZATION_ACCESS_TOKEN=polar_oat_...
To create Polar products, in your Polar dashboard:
Prodcuts > Catalogue page.+ New Product button to create a new product.Recurring subscription pricing.One-time purchase pricing.Create Product.⠇ icon next to your product and select Copy Product ID.Product ID to your .env.server file.
Open SaaS by default expects three products, two subscriptions and one one-time purchase plan:
PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=<your-hobby-product-id>
PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=<your-pro-product-id>
PAYMENTS_CREDITS_10_PLAN_ID=<your-credits-product-id>
:::note[Naming products differently]
Note that if you change names of your products, you'll need to update your app code in src/payment/plans.ts and src/payment/paymentProcessorPlans.ts to match these names as well.
:::
Polar notifies your Wasp app about customer and payment events through a webhook. However, to make it available to Polar during development, you need to expose your locally running Wasp server (started with wasp start) to the internet.
You can do that by running ngrok on port 3001 (Wasp server runs on port 3001 by default). ngrok will then generate a public URL that we can provide to Polar:
ngrok.ngrok is installed and your Wasp app is running, run:
ngrok http 3001
ngrok will display a forwarding address. Copy this address and append /payments-webhook to it. It should look something like this:
https://89e5-2003-c7-153c-72a5-f837.ngrok-free.app/payments-webhook
Next, configure the webhook in your Polar dashboard:
Settings > Webhooks page.Add Endpoint button.ngrok forwarding address with /payments-webhook appended (for example: https://abc123.ngrok-free.app/payments-webhook).Format to "Raw".order.paidsubscription.updatedSave..env.server file:
POLAR_WEBHOOK_SECRET=polar_whs_...
Before testing payments, make sure that you created and set all the required env variables in .env.server (POLAR_ORGANIZATION_ACCESS_TOKEN, <NAME>_PLAN_ID and POLAR_WEBHOOK_SECRET ) and that your ngrok tunnel is running.
You can then test the payment flow:
Buy button for any product on the homepage.To verify everything executed correctly you can:
Settings > Webhooks pageDetails button of your previously created webhook.User table:
wasp db studio
localhost:5555 and check the User table.subscriptionStatus is active for the user who made the purchase.
<Image src={polarUserTable} alt="User table showing updated user" loading="lazy" />