Skip to main content

Payment Configuration

The template supports multiple payment providers and flexible billing workflows. This reference covers every payment-related constant, enum, and configuration option.

Payment Constants

All core payment enums and types are defined in lib/constants/payment.ts. This file is intentionally kept separate from the main config module so it can be imported in scripts that run outside the Next.js runtime (migrations, seeds, CLI tools).

PaymentFlow

Determines when payment is collected relative to the submission process.

export enum PaymentFlow {
PAY_AT_START = 'pay_at_start',
PAY_AT_END = 'pay_at_end',
}
ValueDescription
pay_at_startUser pays before submitting; item is published immediately
pay_at_endUser submits first; payment is collected after admin approval

PaymentStatus

Tracks the state of a payment attempt.

export enum PaymentStatus {
PENDING = 'pending',
PAID = 'paid',
FAILED = 'failed',
}

PaymentInterval

Billing frequency options.

export enum PaymentInterval {
DAILY = 'daily',
WEEKLY = 'weekly',
MONTHLY = 'monthly',
YEARLY = 'yearly',
ONE_TIME = 'one-time',
PER_SUBMISSION = 'per-submission',
}

PaymentPlan

Available subscription tiers.

export enum PaymentPlan {
FREE = 'free',
STANDARD = 'standard',
PREMIUM = 'premium',
}

PaymentProvider

Supported payment gateways.

export enum PaymentProvider {
STRIPE = 'stripe',
SOLIDGATE = 'solidgate',
LEMONSQUEEZY = 'lemonsqueezy',
POLAR = 'polar',
}

Payment Configuration Schema

Defined in lib/config/schemas/payment.schema.ts and validated at startup with Zod.

Product Pricing (Display Values)

pricing: {
free: number; // Default: 0
standard: number; // Default: 10
premium: number; // Default: 20
}
Env VarFieldDefault
NEXT_PUBLIC_PRODUCT_PRICE_FREEpricing.free0
NEXT_PUBLIC_PRODUCT_PRICE_STANDARDpricing.standard10
NEXT_PUBLIC_PRODUCT_PRICE_PREMIUMpricing.premium20

Trial Configuration

Env VarFieldDescription
NEXT_PUBLIC_STANDARD_TRIAL_AMOUNT_IDtrial.standardTrialAmountIdPrice ID for standard trial
NEXT_PUBLIC_PREMIUM_TRIAL_AMOUNT_IDtrial.premiumTrialAmountIdPrice ID for premium trial
NEXT_PUBLIC_AUTHORIZED_TRIAL_AMOUNTtrial.authorizedEnable trial amounts (true/false)

Provider Setup

Stripe

Auto-enabled when both secretKey and publishableKey are present.

Env VarRequiredDescription
STRIPE_SECRET_KEYYesServer-side API key
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYYesClient-side publishable key
STRIPE_WEBHOOK_SECRETRecommendedWebhook signature verification
NEXT_PUBLIC_STRIPE_FREE_PRICENoPrice ID for free plan
NEXT_PUBLIC_STRIPE_STANDARD_PRICE_IDNoPrice ID for standard plan
NEXT_PUBLIC_STRIPE_PREMIUM_PRICE_IDNoPrice ID for premium plan
NEXT_PUBLIC_STRIPE_DYNAMIC_PRICINGNoSet true to fetch prices from Stripe API

LemonSqueezy

Auto-enabled when both apiKey and storeId are present.

Env VarRequiredDescription
LEMONSQUEEZY_API_KEYYesAPI key from LemonSqueezy dashboard
LEMONSQUEEZY_STORE_IDYesYour store identifier
LEMONSQUEEZY_WEBHOOK_SECRETRecommendedWebhook signature verification
LEMONSQUEEZY_WEBHOOK_URLNoOverride webhook endpoint URL
LEMONSQUEEZY_TEST_MODENoSet true for test mode
LEMONSQUEEZY_VARIANT_IDNoDefault variant ID

Polar

Auto-enabled when both accessToken and organizationId are present.

Env VarRequiredDescription
POLAR_ACCESS_TOKENYesAPI access token
POLAR_ORGANIZATION_IDYesOrganization identifier
POLAR_WEBHOOK_SECRETRecommendedWebhook signature verification
POLAR_SANDBOXNoSet false for production (default: true)
POLAR_API_URLNoOverride API base URL

Solidgate

Requires manual environment variable configuration.

Env VarRequiredDescription
SOLIDGATE_API_KEYYesAPI key
SOLIDGATE_SECRET_KEYYesSecret key for signing
SOLIDGATE_WEBHOOK_SECRETYesWebhook verification
SOLIDGATE_MERCHANT_IDYesMerchant identifier
NEXT_PUBLIC_SOLIDGATE_PUBLISHABLE_KEYNoClient-side key

Multi-Currency Billing

Each provider supports per-currency pricing via the billing config modules in lib/config/billing/.

Billing Config Types

type CurrencyCode = 'usd' | 'eur' | 'gbp' | 'cad';
type PlanName = 'premium' | 'standard' | 'free';

interface AmountConfig {
monthly?: string; // Price/variant ID for monthly billing
yearly?: string; // Price/variant ID for yearly billing
setupFee?: string; // Optional setup fee price ID
}

interface CurrencyConfig {
amount: AmountConfig;
currency?: string; // ISO 4217 code (e.g., 'USD')
symbol?: string; // Display symbol (e.g., '$')
}

type PlanConfig = {
productId: string | undefined;
} & Partial<Record<CurrencyCode, CurrencyConfig>>;

Supported Currencies

The SUPPORTED_CURRENCIES array in lib/config/billing/types.ts lists all 32 ISO 4217 codes accepted by the system (USD, EUR, GBP, JPY, CNY, CAD, AUD, CHF, and more).

Price Resolution Functions

Each provider exports a price config function:

ProviderFunctionSource
StripegetStripePriceConfig(plan, currency, interval)billing/stripe.config.ts
LemonSqueezygetLemonSqueezyPriceConfig(plan, currency, interval)billing/lemonsqueezy.config.ts
PolargetPolarPriceConfig(plan, currency, interval)billing/polar.config.ts

All functions fall back to USD if the requested currency is not configured.

Payment Flow Configuration

Defined in lib/config/payment-flows.ts, the PAYMENT_FLOWS array configures the two payment flow options with their UI properties:

interface PaymentFlowConfig {
id: PaymentFlow;
title: string;
subtitle: string;
description: string;
icon: string; // Lucide icon name
color: string; // Tailwind gradient classes
features: string[]; // Feature bullet points
benefits: Array<{ icon: string; text: string; color: string }>;
badge?: string; // Optional badge label
isDefault?: boolean; // Whether this is the default flow
}

Helper functions:

  • getDefaultPaymentFlow() -- returns the default PaymentFlow value
  • getPaymentFlowConfig(flowId) -- returns the PaymentFlowConfig for a given flow

Payment Provider Manager

The PaymentProviderManager class in lib/payment/config/payment-provider-manager.ts provides singleton access to provider instances:

// Get a specific provider
const stripe = PaymentProviderManager.getStripeProvider();
const ls = PaymentProviderManager.getLemonsqueezyProvider();
const polar = PaymentProviderManager.getPolarProvider();
const sg = PaymentProviderManager.getSolidgateProvider();

// Or use the generic function
import { getOrCreateProvider } from '@/lib/payment/config/payment-provider-manager';
const provider = getOrCreateProvider('stripe');