Polar Setup

Connect Polar billing to your Next.js Prisma application

Connect Polar by generating an access token, setting environment variables, creating products in the dashboard, and optionally configuring webhooks. As a merchant of record, Polar handles taxes and compliance.

This page is part of the Billing & Subscriptions documentation.

The Polar integration uses Better Auth's Polar plugin for checkout sessions, customer records, and subscription management, with Polar serving as merchant of record for tax and compliance.

Organization Billing Limitations

Polar lacks true per-organization customers like Stripe. In Makerkit:

  • Organization billing UI works (using referenceId = organization.id)
  • However, customer context remains user-centric with no org "customerId"
  • The customer portal operates at user level, not organization level

For strict B2B billing with dedicated org customers, use Stripe instead.

Before You Start

  • A Polar account (polar.sh)
  • Access to your .env file

Step 1: Enable Polar

Set Polar as your provider in .env:

NEXT_PUBLIC_BILLING_PROVIDER=polar

Also add:

# Required for server-side return URLs
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Step 2: Create Access Token

  1. Sign in to Polar Dashboard
  2. Go to SettingsDevelopersPersonal Access Tokens
  3. Click Create Token
  4. Name it and select required scopes
  5. Copy the token

Add to .env:

POLAR_ACCESS_TOKEN=polar_at_...your_access_token

Recommended scopes:

  • benefits:read
  • checkouts:read
  • checkout:write
  • customer_seats:read
  • customer_portal:read
  • customer_portal:write
  • customer_sessions:write
  • subscriptions:read
  • subscriptions:write
  • customers:read
  • customers:write
  • meters:read
  • meters:write

Add more scopes as needed, like orders:read and orders:write for order management.

Step 3: Set Environment Mode

Configure the environment:

# For development/testing
POLAR_ENVIRONMENT=sandbox
# For production
POLAR_ENVIRONMENT=production

Default is sandbox when not set.

Step 4: Create Products

Via Polar Dashboard

  1. Navigate to Products in your Polar dashboard
  2. Click Create Product
  3. Configure your product:
  • Name: Set the name and description
  • Pricing: Choose pricing (subscription or one-time)
  • Billing Interval: Set billing interval (monthly/yearly)
  • Trial Period: Set the trial period (optional)
  • Meters: Optionally, add metered usage:
    • Example: "requests": $0.10 per 1,000 requests
  • Benefits: Optionally, add benefits
    • Example: "core-features", "email-support", "priority-support"
  1. Copy each Product ID

Sample Products

Starter Product

  • Monthly: prod_starter_monthly ($9.99/month)
  • Yearly: prod_starter_yearly ($99.99/year)

Pro Product

  • Monthly: prod_pro_monthly ($19.99/month)
  • Yearly: prod_pro_yearly ($199.99/year)

Store Product IDs

Add Product IDs to .env:

POLAR_PRODUCT_STARTER_MONTHLY=prod_...
POLAR_PRODUCT_STARTER_YEARLY=prod_...
POLAR_PRODUCT_PRO_MONTHLY=prod_...
POLAR_PRODUCT_PRO_YEARLY=prod_...

Trial Periods

For Polar, configure free trials in the product setup, not the billing config.

Step 5: Map Plans in Config

Update your billing configuration:

import { BillingConfig } from '@kit/billing';
export const billingConfig: BillingConfig = {
products: [
{
id: 'starter',
name: 'Starter',
description: 'For individuals and small teams',
currency: 'USD',
features: ['Core features', 'Email support'],
plans: [
{
name: 'starter-monthly',
planId: process.env.POLAR_PRODUCT_STARTER_MONTHLY!,
displayName: 'Starter Monthly',
interval: 'month',
cost: 9.99,
},
],
},
],
};

Step 6: Set Up Webhooks (Optional)

Webhooks enable server-side lifecycle hooks for logging, analytics, and provisioning in response to Polar events.

Production Setup

  1. In Polar Dashboard, navigate to SettingsWebhooks
  2. Click Add Webhook
  3. Set endpoint URL: https://yourdomain.com/api/auth/polar/webhook
  4. Select events to listen for:
    • subscription.created
    • subscription.updated
    • subscription.canceled
    • order.paid
  5. Copy the webhook signing secret

Add to your .env:

POLAR_WEBHOOK_SECRET=whsec_...

For local development, use a tunneling service like ngrok to receive events.

Local Development

Use ngrok or Localtunnel for local testing:

# Start ngrok
ngrok http 3000
# Use the https URL in Polar webhook settings
# Example: https://abc123.ngrok.io/api/auth/polar/webhook

The proxy URL (e.g., https://abc123.ngrok.io) must be configured in Polar's webhook settings.

Step 7: Verify Integration

Test Checkout Flow

  1. Start development: pnpm dev
  2. Open /settings/billing
  3. Choose a plan and checkout
  4. Complete the flow on Polar

Confirm Webhooks

Check server logs for incoming webhook events.

Environment Variables

Full Polar configuration:

# Billing Provider
NEXT_PUBLIC_BILLING_PROVIDER=polar
# Polar Configuration
POLAR_ACCESS_TOKEN=polar_at_...
POLAR_ENVIRONMENT=sandbox # or 'production'
POLAR_WEBHOOK_SECRET=whsec_...
# Optional behavior toggle (default shown)
CREATE_CUSTOMER_ON_SIGN_UP=true
# Product IDs (from Polar Dashboard)
POLAR_PRODUCT_STARTER_MONTHLY=prod_...
POLAR_PRODUCT_STARTER_YEARLY=prod_...
POLAR_PRODUCT_PRO_MONTHLY=prod_...
POLAR_PRODUCT_PRO_YEARLY=prod_...
# Application URL (for redirects)
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Feature Support

Polar capabilities:

FeatureSupportedNotes
CheckoutYesVia Better Auth API
Customer PortalYesCustomers manage subscriptions here
Cancel (API)NoUse portal for cancellation
Restore (API)NoUse portal for restoration
BenefitsYesProvider feature; not mapped to BillingClient entitlements in Makerkit
Usage MetersYesEvent-based metering
OrganizationsLimitedNo organization customer context; prefer Stripe for B2B billing

Self-Service Portal

Customers manage subscriptions (cancel, restore, upgrade, downgrade) through Polar's customer portal.

Launch Checklist

Before going live:

  • [ ] Set POLAR_ENVIRONMENT to production
  • [ ] Configure production webhook endpoint
  • [ ] Verify webhook events in production
  • [ ] Confirm product IDs match your config
  • [ ] Enable billing notifications in Polar

Troubleshooting

Webhook Verification Fails

Verify POLAR_WEBHOOK_SECRET matches the Polar Dashboard webhook.

Customer Not Created

Confirm createCustomerOnSignUp: true (the default) is set.

Product ID Not Found

Check Product IDs exist in Polar Dashboard and match your config.

Environment Mismatch

Ensure POLAR_ENVIRONMENT matches your Polar mode (sandbox vs production).

Event Hooks

Polar-specific hooks live in packages/billing/polar/src/hooks/:

HookWhen it's called
onSubscriptionCreatedNew subscription created
onSubscriptionUpdatedSubscription changes
onSubscriptionCanceledSubscription canceled
onOrderPaidOrder payment completed
onCustomerCreatedCustomer record created
onCustomerStateChangedCustomer state changes

See Lifecycle Hooks for implementation details.

Watch Out For

  • Price IDs instead of Product IDs: Polar uses Product IDs (prod_...), opposite of Stripe's Price IDs.
  • Expecting org-level customers: Polar is user-centric. No organization.stripeCustomerId equivalent exists.
  • freeTrial in billing config: Polar trials are configured in their dashboard, not MakerKit's config.
  • Wrong POLAR_ENVIRONMENT: Development uses sandbox, production uses production. Mismatch causes auth failures.
  • No webhook setup: Without webhooks, subscription state stalls after checkout. No local CLI forwarder exists, so use ngrok.
  • Expecting API cancel/restore: Polar lacks these APIs. Direct users to the customer portal instead.

Frequently Asked Questions

How do I test Polar without real payments?
Set POLAR_ENVIRONMENT=sandbox. The sandbox environment provides test checkout flows without processing real payments.
Why can't I cancel subscriptions programmatically?
Polar doesn't expose cancel/restore APIs. Redirect users to the customer portal via billing.portal() for subscription management.
Can I use Polar for B2B (organization) billing?
The UI works, but Polar has no organization customer concept. For strict B2B billing with per-org customer records, use Stripe instead.
How do I handle webhook development locally?
Use ngrok or similar to expose your local server: ngrok http 3000. Then configure that URL in Polar's webhook settings.
What happened to Polar benefits?
Polar supports benefits, but MakerKit doesn't map them to BillingClient entitlements. Use billing.getProviderClient() to access benefits directly.

Next: Lifecycle Hooks →