This project uses Polar with Better Auth for subscription management and payments.
Add these to your .env file:
# Polar Configuration
POLAR_ACCESS_TOKEN=your_polar_access_token_here
POLAR_MONTHLY_PRODUCT_ID=your_monthly_product_id
POLAR_YEARLY_PRODUCT_ID=your_yearly_product_id
# Optional: Webhook secret (for production)
POLAR_WEBHOOK_SECRET=your_webhook_secret- Visit polar.sh and create an account
- Create your organization
- Go to your Polar Organization Settings
- Navigate to the "API" section
- Create an Organization Access Token
- Copy the token and add it to your
.envfile asPOLAR_ACCESS_TOKEN
Create three products in your Polar dashboard:
- Type: Subscription
- Billing Interval: Monthly
- Price: $3/month
- Copy the Product ID and set as
POLAR_MONTHLY_PRODUCT_ID
- Type: Subscription
- Billing Interval: Yearly
- Price: $30/year (pay for 10 months only)
- Copy the Product ID and set as
POLAR_YEARLY_PRODUCT_ID
For development, use Polar's sandbox environment:
- The Better Auth integration automatically uses
sandboxwhenNODE_ENV !== "production"
For production, ensure:
NODE_ENV=production- Use production Polar access tokens and product IDs
- Set up webhooks (optional for basic functionality)
- Location:
/src/components/landing/pricing-section.tsx - Functionality:
- Handles authentication checks
- Prevents duplicate subscriptions
- Shows appropriate button states
- Redirects to Polar checkout
- API Used:
authClient.customer.state() - Returns: Complete customer information including:
- Active subscriptions
- Purchase history (orders)
- Granted benefits
- Usage meters
- Route:
/app - Features:
- Subscription status overview
- Quick access to customer portal
- Profile management
// Check if user is authenticated before allowing checkout
if (!session?.user) {
toast.error("Please sign in to purchase a plan");
return;
}// Always check customer state before operations
const { data } = await authClient.customer.state();
const hasActiveSubscription = data.subscriptions?.some(sub => sub.status === "active");// Use Better Auth Polar checkout with product slugs
await authClient.checkout({
slug: "monthly" | "yearly",
});// Redirect to Polar customer portal for subscription management
await authClient.customer.portal();The application implements access control based on customer state:
- Free Users: Access to basic chat features
- Subscription Users: Access to premium features + dashboard
- New Users: Polar customers are automatically created when they sign up (due to
createCustomerOnSignUp: true) - Existing Users: May not have Polar customer records yet, which is normal
The application gracefully handles cases where users don't have Polar customer records:
- Shows appropriate UI states
- Allows checkout (Polar creates customer automatically)
- Provides helpful error messages
- Doesn't break the user experience
When an existing user makes their first purchase:
- Polar automatically creates a customer record
- Customer state becomes available
- Dashboard features become fully functional
- Add your Polar credentials to
.env - Create products in Polar dashboard
- Test checkout flow in sandbox mode
- Set up webhooks for production (optional)
- Customize pricing and product features as needed
For issues related to:
- Better Auth: Check Better Auth docs
- Polar: Check Polar docs or Polar GitHub
- This integration: Open an issue in this repository