Payment Integration
Stripe
Configure the default Stripe payment provider for subscriptions, Checkout, Customer Portal, and Price IDs.
ShipNext's default payment provider is Stripe. The provider is selected in config/website.ts:
const paymentConfig = {
provider: "stripe",
planChange: {
chargeStrategy: "flat_difference",
},
testingEnabled: false,
};Provider code lives in src/integrations/payment/stripe/; business code talks to it through getPaymentProvider().
Configuration locations
| Item | Location | Description |
|---|---|---|
| Provider selection | config/website.ts | payment.provider = "stripe" |
| Plans and entitlements | src/modules/billing/config/plan.ts | Free, starter, pro, Price IDs, credits |
| Checkout API | app/api/payment/checkout/route.ts | Creates Stripe Checkout Sessions |
| Billing Portal | app/api/payment/portal/route.ts | Opens Stripe Customer Portal |
| Webhook | app/api/payment/webhook/route.ts | Syncs subscriptions, orders, and entitlements |
Environment variables
NEXT_PUBLIC_STARTER_MONTHLY_PRICE_ID=''
NEXT_PUBLIC_STARTER_YEARLY_PRICE_ID=''
NEXT_PUBLIC_PRO_MONTHLY_PRICE_ID=''
NEXT_PUBLIC_PRO_YEARLY_PRICE_ID=''
STRIPE_SECRET_KEY=''
STRIPE_WEBHOOK_SECRET=''Public Price IDs are read by plan.ts and used by pricing and Checkout. STRIPE_SECRET_KEY is server-only. Use sk_test_... for testing and sk_live_... in production.
Stripe Dashboard setup
- Create Products and Prices for
starterandpro, monthly and yearly. - Keep displayed amounts in
plan.tsaligned with Stripe Price amounts. - Put Price IDs in the matching
NEXT_PUBLIC_*_PRICE_IDvariables. - Enable Customer Portal and configure subscription, payment method, and invoice options.
- Configure the webhook endpoint:
https://<your-domain>/api/payment/webhookFor local testing:
stripe listen --forward-to localhost:3000/api/payment/webhookCopy the CLI whsec_... value into STRIPE_WEBHOOK_SECRET.
Current boundaries
- Checkout success and cancel URLs use
NEXT_PUBLIC_APP_URLand redirect to/dashboard/settings/billing. PAYMENT_TESTING_ENABLEDreferences older test paths and an unimplemented/api/payment/test; do not treat it as production-ready without fixing that test flow.websiteConfig.payment.testingEnabledexists, but runtime behavior mostly depends onPAYMENT_TESTING_ENABLED.
Checklist
-
NEXT_PUBLIC_APP_URLmatches the current environment. - Every enabled paid price has a real Stripe Price ID.
- Pricing CTA opens Checkout for logged-in users.
- Webhook syncs subscriptions and entitlements after payment.
- Production disables or removes payment test mode.
See Payment webhooks for event processing details.