Skip to main content
Vibestrap’s payment system is designed for template users first: configure a product, pass a productId, and let the starter handle checkout, webhooks, orders, credits, licenses, and the billing portal.

The quick path

For most products you only touch three places:
  1. Create Products + Prices in Stripe.
  2. Paste the price IDs into .env.local.
  3. Adjust plans and packs in src/config/site.ts.
The checkout call stays small:
For links that should work before login, send buyers to:
Unauthenticated buyers are redirected to login, then returned to /checkout and sent to the hosted checkout page automatically.

Config layers

siteConfig.billing is the beginner-facing surface:
siteConfig.demoPlans defines the four demo SaaS tiers your app sells. siteConfig.payment is the advanced provider layer: Stripe is enabled by default; Creem and NOWPayments can be added when you need alternate rails.

Provider facade

Provider code still lives behind one contract:
Stripe, Creem, and NOWPayments each normalize webhooks to the same NormalizedEvent shape. The shared handler in src/payment/handlers/core.ts inserts the payment row, grants credits, issues licenses, and records affiliate commission.

Idempotency

Provider retries are expected. The payment table has unique indexes on both invoiceId and sessionId; the handler inserts with conflict protection and then grants entitlements idempotently by paymentId. That means replaying a webhook should not create duplicate payments, credits, licenses, or affiliate commissions.

Provider notes

Verify it works

  1. Set Stripe keys and price IDs in .env.local.
  2. Run pnpm dev.
  3. Open /checkout?productId=pro.
  4. Complete a test payment.
  5. Confirm a row appears in payment and the expected credits/license are granted.
  6. Replay the webhook; the database should stay unchanged.