Overview
aSaaSin uses Polar for subscriptions and one-time purchases. Pricing is displayed from the database, and a webhook grants benefits (Discord role, repo/file access) after successful checkout.
What you get
- One-click checkout with Polar
- Monthly & yearly subscriptions
- One-time purchases (guest checkout)
- Webhook-based benefit delivery
- Public, read-only pricing table
Flows at a glance
Subscription flow
- Unauthenticated user clicks Subscribe → redirected to sign-up with
?variant_id=<polar-product-id>&redirect_to=/checkout. - After auth,
/auth/callbackreads params →SubscribeRedirectorcreates a Polar checkout session server-side. - User completes payment on Polar's hosted page → redirected to
POLAR_SUCCESS_URL(must include{CHECKOUT_ID}placeholder).
One-time purchase flow
- User clicks Buy → server action creates Polar checkout session → user redirected to Polar.
- Polar redirects to
POLAR_SUCCESS_URLon completion. - Success page reads
checkout_idfrom query params and finalizes fulfillment.
Webhook setup
Webhooks keep your database in sync with Polar. Configure the endpoint in Polar → Webhooks: https://yourdomain.com/api/webhooks/polar.
Required events:
subscription.created— new subscription activatedsubscription.updated— plan change or renewalsubscription.canceled— subscription endedorder.created— one-time purchase completedorder.refunded— refund issued
// app/api/webhooks/polar/route.ts (simplified)
export async function POST(req: Request) {
const body = await req.text()
const signature = req.headers.get('webhook-signature') ?? ''
const event = await polar.webhooks.constructEvent(body, signature, process.env.POLAR_WEBHOOK_SECRET!)
if (event.type === 'subscription.created' || event.type === 'subscription.updated') {
// Map event.data.productId → subscription_plans.id
// Upsert into subscriptions table
}
if (event.type === 'subscription.canceled') {
// Set subscriptions.status = 'canceled', store canceled_at
}
}The handler resolves product_id to an internal subscription_plan_id via the subscription_plans table where polar_product_id matches. Always make webhook handlers idempotent — Polar may deliver the same event more than once.
Environment variables
POLAR_API_KEY— API key from the Polar dashboard.POLAR_WEBHOOK_SECRET— used to verify the signature on each webhook request.POLAR_SUCCESS_URL— redirect URL after checkout; must include the{CHECKOUT_ID}placeholder, e.g.https://yourdomain.com/success?checkout_id={CHECKOUT_ID}.
For local development, use ngrok to expose your local server and set the tunnel URL as the webhook endpoint in Polar Sandbox. Update POLAR_SUCCESS_URL in .env to use the ngrok URL too.