Payment Configuration
Learn how to configure pricing and payment plans for both Stripe and Creem in NEXTDEVKIT
💰 Payment Types
NEXTDEVKIT supports two payment types with both providers:
export enum PaymentType {
SUBSCRIPTION = "subscription",
ONE_TIME = "one-time",
}
export enum PlanInterval {
MONTH = "monthly",
YEAR = "yearly",
}
🎯 Provider Configuration
First, you need to set up the payment provider in src/config/index.ts
:
payment: {
provider: "stripe", // or "creem"
currency: "USD",
yearlyDiscount: 20,
redirectAfterCheckout: "/app/dashboard",
plans: {
// ... your plan configuration
}
}
Switching Between Providers
To switch from Stripe to Creem or vice versa:
- Update the provider:
// For Stripe
provider: "stripe"
// For Creem
provider: "creem"
- Update environment variables:
# For Stripe
STRIPE_SECRET_KEY="sk_test_your_key"
STRIPE_WEBHOOK_SECRET="whsec_your_secret"
# For Creem
CREEM_API_KEY="ck_test_your_key"
CREEM_WEBHOOK_SECRET="your_webhook_secret"
- Update Price/Product IDs:
# The same environment variable names work for both providers
NEXT_PUBLIC_PRICE_ID_PRO_MONTHLY="your_monthly_id"
NEXT_PUBLIC_PRICE_ID_PRO_YEARLY="your_yearly_id"
NEXT_PUBLIC_PRICE_ID_LIFETIME="your_lifetime_id"
📋 Define Plans and Products
You can manage the plans and products in the configuration file of your NEXTDEVKIT project. There are different types of plans you can define:
🆓 Free Plan
The free plan is the default plan for users who have not purchased any plans or can be used to access a limited version of your product.
As this is no paid plan, you don't need to define any prices or attach a product id to it.
export const appConfig = {
payment: {
plans: {
free: {
id: "free",
isFree: true,
},
}
},
};
🏢 Enterprise Plan
The enterprise plan is not a real plan, but will show up in the pricing table with a link to a contact form, so customers can contact you to get access to your product.
As this is no paid plan, you don't need to define any prices or attach a product id to it.
export const appConfig = {
payment: {
plans: {
enterprise: {
id: "enterprise",
isEnterprise: true,
highlighted: true,
},
}
},
};
🔄 Subscription Plans and 💎 One-time Purchase Plans
A plan represents a product or service of your application and each is a column in your pricing table. It has the following properties:
popular
: if this plan should be highlighted as recommended ⭐highlighted
: highlight the plan from the pricing table ✨prices
: define the prices for this plan 💰
One plan can have multiple prices, for example a monthly and yearly price or/and for each currency you support.
A price has the following properties:
type
: the type of the price, can bePaymentType.SUBSCRIPTION
orPaymentType.ONE_TIME
priceId
: the id of the product from your payment provider 🆔interval
: the interval of the price, can bePlanInterval.MONTH
orPlanInterval.YEAR
amount
: the amount of the price 💵trialPeriodDays
: the number of days of the trial period, leave out if you don't want to offer a trial period 🎁
Complete Plan Configuration Example
payment: {
provider: "stripe", // or "creem"
currency: "USD",
yearlyDiscount: 20,
redirectAfterCheckout: "/app/dashboard",
plans: {
free: {
id: "free",
isFree: true,
},
pro: {
id: "pro",
prices: [
{
type: PaymentType.SUBSCRIPTION,
priceId: process.env.NEXT_PUBLIC_PRICE_ID_PRO_MONTHLY as string,
amount: 9.9,
interval: PlanInterval.MONTH,
trialPeriodDays: 7,
},
{
type: PaymentType.SUBSCRIPTION,
priceId: process.env.NEXT_PUBLIC_PRICE_ID_PRO_YEARLY as string,
amount: 99,
interval: PlanInterval.YEAR,
trialPeriodDays: 30,
},
],
popular: true,
},
lifetime: {
id: "lifetime",
prices: [
{
type: PaymentType.ONE_TIME,
priceId: process.env.NEXT_PUBLIC_PRICE_ID_LIFETIME as string,
amount: 399,
},
],
isLifetime: true,
},
enterprise: {
id: "enterprise",
isEnterprise: true,
highlighted: true,
},
},
}
🔧 Provider-Specific Notes
Stripe Configuration
priceId
: Use Stripe Price IDs (starts withprice_
)- Products: Create products and prices in Stripe Dashboard
- Webhooks: Set up webhook endpoint at
/api/webhooks/stripe
Creem Configuration
priceId
: Use Creem Product IDs (starts withprod_
)- Products: Create products in Creem Dashboard
- Webhooks: Set up webhook endpoint at
/api/webhooks/creem
📝 Plan Information for Pricing Table
You can define the information for the pricing table for each plan in src/config/marketing/pricing.ts
.
You can define a title, a description and a features array for each plan.
We recommend you to use the t()
function to get the translations for the plan information and then define the translations in the /messages/
folder.
export async function getPricingConfig(): Promise<PricingConfig> {
const t = await getTranslations("pricing");
const priceConfig = appConfig.payment;
const plans: PricePlan[] = [];
if (priceConfig.plans.free) {
plans.push({
...priceConfig.plans.free,
name: t("products.free.title"),
description: t("products.free.description"),
features: [
t("products.free.features.feature1"),
t("products.free.features.feature2"),
t("products.free.features.feature3"),
],
});
}
if (priceConfig.plans.pro) {
plans.push({
...priceConfig.plans.pro,
name: t("products.pro.title"),
description: t("products.pro.description"),
features: [
t("products.pro.features.feature1"),
t("products.pro.features.feature2"),
t("products.pro.features.feature3"),
t("products.pro.features.feature4"),
],
});
}
if (priceConfig.plans.lifetime) {
plans.push({
...priceConfig.plans.lifetime,
name: t("products.lifetime.title"),
description: t("products.lifetime.description"),
features: [
t("products.lifetime.features.feature1"),
t("products.lifetime.features.feature2"),
t("products.lifetime.features.feature3"),
],
});
}
if (priceConfig.plans.enterprise) {
plans.push({
...priceConfig.plans.enterprise,
name: t("products.enterprise.title"),
description: t("products.enterprise.description"),
features: [
t("products.enterprise.features.feature1"),
t("products.enterprise.features.feature2"),
t("products.enterprise.features.feature3"),
t("products.enterprise.features.feature4"),
t("products.enterprise.features.feature5"),
],
});
}
return {
title: t("title"),
subtitle: t("subtitle"),
frequencies: [t("frequencies.monthly"), t("frequencies.yearly")],
yearlyDiscount: priceConfig.yearlyDiscount,
plans,
};
}
🧪 Testing Configuration
Environment Variables for Testing
# Stripe Test Mode
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_test_..."
# Creem Test Mode
CREEM_API_KEY="ck_test_..."
CREEM_WEBHOOK_SECRET="test_webhook_secret"
# Test Price/Product IDs
NEXT_PUBLIC_PRICE_ID_PRO_MONTHLY="test_price_monthly"
NEXT_PUBLIC_PRICE_ID_PRO_YEARLY="test_price_yearly"
NEXT_PUBLIC_PRICE_ID_LIFETIME="test_price_lifetime"
🔧 Troubleshooting Configuration
Common Configuration Issues
Provider Not Found:
- Check that
provider
is set to either "stripe" or "creem" - Verify the correct provider implementation exists
Missing Environment Variables:
- Ensure all required environment variables are set
- Check for typos in variable names
- Verify test vs production keys
Invalid Price/Product IDs:
- Confirm IDs exist in your payment provider dashboard
- Check ID format matches provider requirements
- Verify test vs production IDs
Plan Configuration Errors:
- Ensure plan structure matches expected format
- Check that required fields are present
- Verify data types match interface definitions
🎯 Next Steps
Now that your payment configuration is set up: