TinyShip
TinyShip
 TinyShip
TinyShip
TinyShip Documentation
TinyShip User GuideGetting StartedBasic Configuration
Payment ConfigurationStripe ConfigurationPayPal ConfigurationWeChat Pay ConfigurationAlipay ConfigurationCreem ConfigurationDodo Payments ConfigurationWaffo Pancake ConfigurationDynamic PricingPayment Testing
Credits System ConfigurationAffiliate System Configuration
Storage Service ConfigurationDatabase ConfigurationCaptcha Configuration
Development Best PracticesLocal E2E Workflow
User GuidePayment

Dynamic Pricing

Manage pricing plans in real time from the admin panel, without code changes or redeployment

Dynamic pricing lets you create, edit, and adjust pricing plans directly in the admin panel — no code changes or redeployment needed. The default static pricing (config/payment.ts) is unaffected, and you can switch between the two modes anytime.

Enable Dynamic Pricing

  1. Set in .env:

    PRICING_MODE=dynamic
  2. Make sure the pricing_plan table exists. New versions of the template ship with this table in the schema — a normal database init (pnpm db:push) already includes it. Projects upgraded from older versions need to add the table manually:

    pnpm db:push          # PostgreSQL
    pnpm db:push:sqlite   # SQLite / D1
  3. Restart the app. The pricing page now reads plans from the database.

PRICING_MODE only takes effect on the server. When unset or set to static, behavior is exactly the same as before.

Admin Panel

With dynamic pricing enabled, manage all plans at /admin/pricing:

  • Create / edit plans: set the name, price, currency, type (subscription / lifetime / credit pack), and the provider's Price ID / Product ID
  • Enable / disable: toggle whether a plan appears on the pricing page
  • Reorder: drag to adjust the display order on the pricing page
  • One-click import: import existing static plans from config/payment.ts into the database — ideal for the first migration

Import only creates new records and never overwrites existing plans. Importing repeatedly produces duplicates.

Key Capabilities

Compared to static pricing, dynamic mode adds:

  • Strikethrough pricing: set an originalPrice to show the original price struck through with the discount
  • Multilingual content: each plan can have per-language names, descriptions, and features, with automatic fallback to English
  • Markdown features: the Features field supports Markdown for rich-text highlights
  • Locale filtering: restrict a plan to specific locales (e.g. zh-CN only); the pricing page filters automatically by user language. Plans without a locale are visible to everyone
  • Custom ordering: control display order via sort weight instead of code order

Locale filtering only controls what the pricing page displays — users can still purchase plans from other regions via the API directly.

Migrating from Static to Dynamic

This section is only for existing projects upgraded from an older version. New projects already have the pricing_plan table in their schema — just set PRICING_MODE=dynamic and import or create plans in the admin panel; skip step 1.

  1. Run pnpm db:push (or pnpm db:push:sqlite) to add the pricing_plan table
  2. Click "Import from Config" at /admin/pricing to import existing plans
  3. Review the import, especially each provider's Price / Product ID
  4. Set PRICING_MODE=dynamic and restart
  5. Run a full payment flow in test mode to confirm the pricing page and Webhook callbacks work

Rollback: set PRICING_MODE back to static and restart. Plans in the database are preserved.

Notes

  • Dynamic plans must have the correct provider ID, or payments will fail: stripePriceId for Stripe, creemProductId for Creem, dodoProductId for Dodo, waffoProductId for Waffo (PROD_xxx). WeChat Pay / Alipay need none
  • Fully compatible with the affiliate system — commission is calculated from the actual paid amount, regardless of pricing mode
  • Run pnpm db:seed to generate sample plans for each provider (including Stripe, WeChat Pay, Creem, PayPal, Dodo, Waffo). If plans already exist, seed skips insertion — add new ones manually in the admin panel

Reference

  • Payment Overview — payment methods and static pricing configuration
  • Credits Guide — credit top-up and consumption configuration
  • Payment Testing Guide — local testing and Webhook debugging

Waffo Pancake Configuration

Configure Waffo Pancake payments (Merchant of Record model)

Payment Testing

How to test payment functionality

On this page

Enable Dynamic PricingAdmin PanelKey CapabilitiesMigrating from Static to DynamicNotesReference