Subscriptions
Learn how to manage subscriptions in your application.
TurboStarter supports subscription billing (recurring payments) on the web across providers like Stripe, Lemon Squeezy, and Polar.
Subscriptions are configured in your billing config using:
- plans: what you sell (Free, Premium, Enterprise, etc.)
- variants: how you sell it (monthly, yearly, trials, etc.)
Configuration
Subscriptions are represented as variants with model: BillingModel.RECURRING.
export const config = billingConfigSchema.parse({
plans: [
{
id: BillingPlan.PREMIUM,
name: "Premium",
description: "Become a power user and gain benefits",
badge: "Bestseller",
features: [
"Unlimited projects",
"Priority support",
"Advanced integrations",
"Team collaboration",
"Analytics dashboard",
],
variants: [
// Monthly
{
id: "price_monthly_or_variant_id",
cost: 1900,
currency: "usd",
model: BillingModel.RECURRING,
interval: RecurringInterval.MONTH,
trialDays: 7,
},
// Yearly
{
id: "price_yearly_or_variant_id",
cost: 8900,
currency: "usd",
model: BillingModel.RECURRING,
interval: RecurringInterval.YEAR,
trialDays: 7,
},
],
},
],
}) satisfies BillingConfig;Breaking down the fields:
id: Provider identifier for this recurring price/variant/product.cost: Amount in the smallest currency unit (e.g. cents). Used for UI; provider charges the real amount.currency: Currency code (defaults tousd).model: Must beBillingModel.RECURRING.interval: Required for recurring variants (RecurringInterval.MONTH,RecurringInterval.YEAR, etc.).trialDays: Optional trial length in days.
Match IDs exactly
The variant.id value must match what your billing provider expects (Stripe price ID, Lemon Squeezy variant ID, Polar product ID, etc.). A mismatch is the #1 reason why a checkout can't be created.
Provider notes
- Stripe:
variant.idshould match a Stripe Price ID (price_...). Webhook events used for subscriptions includecustomer.subscription.*. See Stripe setup. - Lemon Squeezy:
variant.idshould match a Lemon Squeezy Variant ID. See Lemon Squeezy setup. - Polar:
variant.idshould match a Polar Product ID (Polar treats each “variant” as a separate product). Subscription events includesubscription.created/subscription.updated. See Polar setup.
How is this guide?
Last updated on