Skip to content
Have an Open SaaS app in production? We'll send you some swag! 👕

Paddle

First, make sure you’ve defined your payment processor in src/payment/paymentProcessor.ts and src/payment/paymentProcessorClient.ts, as described in the important first steps.

Next, you’ll need to create a Paddle account in the sandbox mode. You can do that here.

Paddle features two separate environments:

They are fully isolated from each other, which means that you need to create separate accounts for each of them. They also feature independent products, prices, API keys, etc.

For local development and testing, you’ll want to use Paddle’s sandbox mode. To enable sandbox mode, make sure that PADDLE_SANDBOX_MODE is set to true in your .env.server file, and REACT_APP_PADDLE_SANDBOX_MODE is set to true in your .env.client file:

.env.server
PADDLE_SANDBOX_MODE=true
.env.client
REACT_APP_PADDLE_SANDBOX_MODE=true

When you’re ready to deploy your app, we’ll remind you to set these to false.

Once you’ve created your account, you’ll need to get your API key. You can do that by:

  1. Navigating to My Account > Settings.
  2. Opening the Developer Tools > Authentication page.
  3. Click on the New API key button to create a new key.
  4. Give your key a name (e.g., “Open SaaS Development”).
  5. Select the following permissions:
    • Customer portal sessions: write
    • Customers: read and write
    • Metrics: read
    • Reports: read
    • Transactions: read and write
  6. Copy the generated key and add it to your .env.server file:
    .env.server
    PADDLE_API_KEY=pdl_sdbx_apikey_...

Paddle’s checkout runs in the browser with Paddle.js, which needs a client-side token. You can get one by:

  1. Navigating to My Account > Settings.
  2. Opening the Developer Tools > Authentication page.
  3. Selecting the Client-side tokens tab.
  4. Click on the New client-side token button to create a new token.
  5. Give your token a name (e.g., “Open SaaS Development Client”).
  6. Copy the generated token and add it to your .env.client file:
    .env.client
    REACT_APP_PADDLE_CLIENT_TOKEN=test_...

Paddle requires a default payment link before it can open a checkout. Paddle doesn’t accept localhost URLs, but in sandbox mode the link isn’t actually visited, so you can use https://example.com.

To set it:

  1. Navigate to Checkout > Checkout configuration.
  2. Set the Default payment link to https://example.com.
  3. Click Save.

In production, you’ll need to set it to your deployed app’s URL. We’ll remind you to do that when you deploy your app.

To create Paddle products, in your Paddle dashboard:

  1. Navigate to the Catalog > Products page.
  2. Click on the + New product button to create a new product.
  3. Fill in the product details and click Save.
  4. Click on your newly created product in the Catalog > Products list to open its product page.
  5. On the product page, click on the New Price + button.
    • Fill in the Internal description (e.g. “Monthly”). It’s required, but isn’t shown to your customers.
    • Set the Base price (e.g. 9.99).
    • For subscription products, select a Recurring billing period (e.g. monthly).
    • For one-time payment products, select One-time.
    • Set the quantity to a minimum of 1 and a maximum of 1. Open SaaS grants one plan (or one pack of credits) per purchase, so customers shouldn’t be able to buy more than one at a time.
  6. Click Save.
  7. Copy the Price ID (it starts with pri_). Note that Open SaaS uses the price ID, not the product ID.
  8. Add the Price ID to your .env.server file. Open SaaS by default expects three products, two subscriptions and one one-time purchase plan:
    .env.server
    PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=<your-hobby-price-id>
    PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=<your-pro-price-id>
    PAYMENTS_CREDITS_10_PLAN_ID=<your-credits-price-id>

Exposing your Webhook Endpoint to the Internet

Section titled “Exposing your Webhook Endpoint to the Internet”

Paddle notifies your Wasp app about customer and payment events through a webhook. However, to make it available to Paddle 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 Paddle:

  1. First, make sure you have installed ngrok.
  2. Once ngrok is installed and your Wasp app is running, run:
    Terminal window
    ngrok http 3001
    ngrok
  3. ngrok will display a forwarding address. Copy this address and append /payments-webhook to it. It should look something like this:
    Callback URL
    https://89e5-2003-c7-153c-72a5-f837.ngrok-free.app/payments-webhook

Next, configure the webhook in your Paddle dashboard:

  1. Navigate to the Events > Notifications page.
  2. Click the + New destination button.
  3. Fill in the Description (e.g. “Open SaaS Development”).
  4. Set the Notification Type to Webhook.
  5. In the URL field, paste your ngrok forwarding address with /payments-webhook appended (for example: https://abc123.ngrok-free.app/payments-webhook).
  6. Set the Usage type to Both.
  7. Select the following events to listen for:
    • transaction.completed
    • subscription.updated
    • subscription.canceled
  8. Click Save.
  9. Click on your newly created destination in the Events > Notifications list to open it.
  10. Click copy on the Secret key and add it to your .env.server file:
    .env.server
    PADDLE_WEBHOOK_SECRET=pdl_ntfset_...

Before testing payments, make sure that you created and set all the required env variables in .env.server (PADDLE_API_KEY, <NAME>_PLAN_ID and PADDLE_WEBHOOK_SECRET) and .env.client (REACT_APP_PADDLE_CLIENT_TOKEN), that you set a default payment link, and that your ngrok tunnel is running.

You can then test the payment flow:

  1. Click a Buy button for any product on the homepage.
  2. Paddle’s checkout should open as an overlay on the page.
  3. Fill in the checkout form with test payment information.
  4. Complete the payment.
  5. You should be redirected to the checkout success page.

To verify everything executed correctly you can:

  • Check Paddle webhook event logs:
    1. Navigate to the Events > Notifications page.
    2. Open your previously created destination.
    3. Confirm all of the events have been delivered successfully.
  • Inspect your database’s User table:
    1. Run Wasp DB studio:
      Terminal window
      wasp db studio
    2. Navigate to localhost:5555 and check the User table.
    3. Confirm the subscriptionStatus is active for the user who made the purchase.