Skip to content

Payments

Payment integration powered by Polar.sh via the Better Auth Polar plugin. Sell digital products, subscriptions, or one-time purchases. Checkout, customer portal, and webhooks are wired through Better Auth’s /api/auth endpoints.

Key features

  • One-time payments and subscriptions
  • Automatic role assignment on purchase
  • Email notifications for access changes
  • Ready-to-use checkout button component
  • Webhook handling via @polar-sh/better-auth
  1. Create a Polar account - sign up at polar.sh

  2. Create products - set up your products in the Polar dashboard

  3. Create an Organization Access Token - generate a Polar access token and add it as a secret:

    Terminal window
    bunx wrangler secret put POLAR_ACCESS_TOKEN --env=preview
    Terminal window
    bunx wrangler secret put POLAR_ACCESS_TOKEN --env=production
  4. Configure webhooks - create a webhook endpoint pointing to /api/auth/polar/webhooks and enable these events: order.paid, order.refunded, subscription.active, subscription.revoked

  5. Add the webhook secret - add POLAR_WEBHOOK_SECRET as a secret in Cloudflare for preview and production environments:

    Terminal window
    bunx wrangler secret put POLAR_WEBHOOK_SECRET --env=preview
    Terminal window
    bunx wrangler secret put POLAR_WEBHOOK_SECRET --env=production
  6. Configure your products - add them to packages/config/index.ts:

    payments: {
    products: {
    premium: {
    name: "Premium",
    userRoleToGrant: "premium",
    polarProductId: {
    preview: "your-preview-product-id",
    production: "your-production-product-id",
    },
    },
    },
    }

Each product maps to a user role via userRoleToGrant. When a customer completes payment, they’re automatically granted the corresponding role (see permissions). The role is automatically revoked on refund or subscription cancellation.

A styled button that starts Polar checkout through the Better Auth client. Uses the product config slug.

import { CheckoutButton } from "@/payments/components/checkout-button"
;<CheckoutButton productId="premium">Get Premium Access</CheckoutButton>

The productId must match a key in your payments.products config.

  1. User clicks a CheckoutButton
  2. Better Auth Polar checkout opens Polar’s hosted checkout
  3. After payment, Polar sends a webhook to /api/auth/polar/webhooks
  4. The webhook handler grants the user role and sends a confirmation email
  5. User is redirected to /payments/success

Webhook events handled:

EventAction
order.paidGrant role, send access granted email
subscription.activeGrant role, send access granted email
order.refundedRevoke role, send access revoked email
subscription.revokedRevoke role, send access revoked email