Menu

Pricing Plan Management

Pricing plans are the core of the payment system. They define the products users can purchase, prices, payment methods, and benefits. NEXTY.DEV provides a complete management interface and API to manage pricing plans.

Pricing Plan Data Structure

Basic Fields

{
  id: string;                    // UUID, auto-generated
  environment: 'test' | 'live';   // Environment: test or production
  cardTitle: string;              // Card title
  cardDescription?: string;        // Card description
  provider: 'stripe' | 'creem' | 'none';  // Payment provider
  isActive: boolean;              // Whether activated
  isHighlighted: boolean;         // Whether highlighted
  displayOrder: number;           // Display order
}

Payment Configuration Fields

Stripe Configuration

{
  stripePriceId?: string;         // Stripe Price ID
  stripeProductId?: string;       // Stripe Product ID
  stripeCouponId?: string;        // Stripe Coupon ID
  enableManualInputCoupon: boolean; // Enable manual coupon input entry
}

Creem Configuration

{
  creemProductId?: string;        // Creem Product ID
  creemDiscountCode?: string;      // Creem discount code
}

Payment Type and Interval

{
  paymentType: 'one_time' | 'onetime' | 'recurring' | null; // Stripe and Creem have different definitions, boilerplate preserves provider's original definition
  recurringInterval: 'month' | 'year' | 'every-month' | 'every-year' | null; // Stripe and Creem have different definitions, boilerplate preserves provider's original definition
}

Price Information

{
  price?: string;                 // Actual price (numeric string)
  currency?: string;              // Currency code (e.g., USD, CNY)
  displayPrice?: string;          // Display price (e.g., "$10")
  originalPrice?: string;          // Original price (used to show discount)
  priceSuffix?: string;            // Price suffix (e.g., "month", "year")
}

Multi-language Support (langJsonb)

langJsonb is a JSONB field used to store multi-language content:

{
  "en": {
    "cardTitle": "Pro Plan",
    "cardDescription": "Best for professionals",
    "displayPrice": "$29",
    "priceSuffix": "month",
    "buttonText": "Get Started",
    "features": [
      { "description": "Feature 1", "included": true },
      { "description": "Feature 2", "included": true }
    ]
  },
  "zh": {
    "cardTitle": "专业版",
    "cardDescription": "适合专业人士",
    "displayPrice": "¥199",
    "priceSuffix": "月",
    "buttonText": "立即开始",
    "features": [
      { "description": "功能 1", "included": true },
      { "description": "功能 2", "included": true }
    ]
  }
}

Benefits Configuration (benefitsJsonb)

benefitsJsonb is used to define the benefits granted to users by the plan, especially credits:

{
  "oneTimeCredits": 100,          // One-time credits (one-time payment)
  "monthlyCredits": 50,            // Monthly credits (subscription)
  "totalMonths": 12                // Total months (annual subscription)
}

Features List (features)

The features list is an array used to display the features included in the plan:

[
  {
    "description": "Unlimited projects",
    "included": true,
    "bold": false
  },
  {
    "description": "Priority support",
    "included": true,
    "bold": true
  },
  {
    "description": "Advanced analytics",
    "included": false,
    "bold": false
  }
]

Creating a Pricing Plan

Create via Dashboard

  1. Visit /dashboard/prices (admin privileges required)
  2. Click the "Create Plan" button
  3. Fill in plan information:
    • Basic Information: Title, description, environment
    • Payment Provider: Choose Stripe, Creem, or None
    • Payment Configuration: Fill in corresponding configuration based on the selected provider
    • Price Information: Price, currency, display price, etc.
    • Multi-language Content: Fill in multi-language content in the langJsonb field
    • Benefits Configuration: Configure benefits such as credits in benefitsJsonb
    • Features List: Add features included in the plan

Create via API

Use the createPricingPlanAction function:

import { createPricingPlanAction } from '@/actions/prices/admin';
 
const result = await createPricingPlanAction({
  planData: {
    environment: 'live',
    cardTitle: 'Pro Plan',
    provider: 'stripe',
    stripePriceId: 'price_xxx',
    paymentType: 'recurring',
    recurringInterval: 'month',
    price: '29.00',
    currency: 'USD',
    displayPrice: '$29',
    priceSuffix: 'month',
    isActive: true,
    isHighlighted: false,
    displayOrder: 1,
    langJsonb: {
      en: {
        cardTitle: 'Pro Plan',
        cardDescription: 'Best for professionals',
        displayPrice: '$29',
        priceSuffix: 'month',
        buttonText: 'Get Started',
        features: [
          { description: 'Feature 1', included: true }
        ]
      }
    },
    benefitsJsonb: {
      monthlyCredits: 100
    },
    features: [
      { description: 'Unlimited projects', included: true }
    ]
  },
  locale: 'en'
});

Updating a Pricing Plan

Update via Dashboard

  1. Visit /dashboard/prices
  2. Click on the plan you want to update
  3. Modify plan information
  4. Save changes

Update via API

Use the updatePricingPlanAction function:

import { updatePricingPlanAction } from '@/actions/prices/admin';
 
const result = await updatePricingPlanAction({
  id: 'plan-id',
  planData: {
    displayPrice: '$39',  // Only update fields that need modification
    isHighlighted: true
  },
  locale: 'en'
});

Deleting a Pricing Plan

Delete via Dashboard

  1. Visit /dashboard/prices
  2. Click on the plan you want to delete
  3. Click the delete button
  4. Confirm deletion

Delete via API

Use the deletePricingPlanAction function:

import { deletePricingPlanAction } from '@/actions/prices/admin';
 
const result = await deletePricingPlanAction({
  id: 'plan-id',
  locale: 'en'
});

Querying Pricing Plans

Admin Query for All Plans

import { getAdminPricingPlans } from '@/actions/prices/admin';
 
const result = await getAdminPricingPlans();
if (result.success) {
  const plans = result.data;  // All plans (including inactive ones)
}

Public Query for Active Plans

import { getPublicPricingPlans } from '@/actions/prices/public';
 
const result = await getPublicPricingPlans();
if (result.success) {
  const plans = result.data;  // Returns only active plans
}

The system automatically filters based on the current environment (NODE_ENV):

  • Production environment: Returns plans with environment = 'live'
  • Other environments: Returns plans with environment = 'test'

Query a Single Plan by ID

import { getPricingPlanById } from '@/actions/prices/admin';
 
const result = await getPricingPlanById('plan-id');
if (result.success) {
  const plan = result.data;
}

Displaying Pricing Plans

Using the Pricing Component (Categorized by Type)

The Pricing.tsx component categorizes and displays plans based on payment type:

import Pricing from '@/components/home/Pricing';
 
export default function PricingPage() {
  return <Pricing />;
}

The component automatically:

  • Categorizes plans into monthly subscriptions, annual subscriptions, and one-time payments
  • Uses the Tabs component to switch between different plan types
  • Displays corresponding multi-language content based on the current locale

Using the PricingAll Component (Display All Plans)

The PricingAll.tsx component displays all active plans at once:

import PricingAll from '@/components/home/PricingAll';
 
export default function PricingPage() {
  return <PricingAll />;
}

Custom Styling

You can also modify the styling of the PricingCardDisplay component to meet your needs.

Multi-language Content Management

Language Codes

The system uses standard language codes (e.g., en, zh, ja) to identify different languages.

Multi-language Fields

The following fields support multi-language:

  • cardTitle
  • cardDescription
  • displayPrice
  • originalPrice
  • priceSuffix
  • buttonText
  • highlightText
  • features

Multi-language Fallback Mechanism

If content for the current locale doesn't exist, the system automatically falls back to the default language (usually en):

const localizedPlan = 
  plan.langJsonb?.[currentLocale] || 
  plan.langJsonb?.[DEFAULT_LOCALE] || 
  {};

Benefits Configuration Best Practices

One-time Payment Benefits

{
  "oneTimeCredits": 100
}

After purchasing a one-time plan, users immediately receive 100 credits.

Monthly Subscription Benefits

{
  "monthlyCredits": 50
}

After subscribing to a monthly plan:

  • Immediately receive 50 credits
  • Reset to 50 credits upon each monthly renewal

Annual Subscription Benefits

{
  "monthlyCredits": 50,
  "totalMonths": 12
}

After subscribing to an annual plan:

  • Immediately receive 50 credits
  • Receive 50 credits each subsequent month
  • Total distribution over 12 months

Payment Provider Configuration

Stripe Configuration Steps

  1. Create a Product in Stripe Dashboard
  2. Create a Price (choose one-time or subscription)
  3. Copy the Price ID
  4. Fill in stripePriceId in the pricing plan

Creem Configuration Steps

  1. Create a Product in Creem Dashboard
  2. Copy the Product ID
  3. Fill in creemProductId in the pricing plan

Coupon Configuration

Stripe Coupons

  • Create a Coupon in Stripe Dashboard
  • Select the created Coupon in the pricing plan, no need to manually fill it in
  • For Stripe pricing, if a default Coupon is set, manual coupon modification is not allowed. You can enable manual coupon input entry through the enableManualInputCoupon field

Creem Discount Codes

  • Create a Discount Code in Creem Dashboard
  • Fill it into the creemDiscountCode field

Frequently Asked Questions

Q: How do I create a free plan?

A: Set provider = 'none'. This way, the plan will be displayed but won't trigger the payment process. You can use the buttonLink field to set a custom link to guide users to the feature usage page.

Q: How do I hide a plan?

A: Set isActive = false. The plan will not be returned in the public API and will not be displayed on the pricing page.

Q: How do I adjust the display order of plans?

A: Modify the displayOrder field. The smaller the number, the higher it appears in the display order.