Swap Stripe for Paddle
Paddle acts as a merchant of record, so it handles sales tax and VAT for you. Because payments sit behind a thin layer in ShipVeryFast, the swap touches a handful of files, not your whole app. Read the billing model first, the one rule (the webhook is the source of truth) is identical with Paddle.
The seam
app/api/checkout/session/route.ts, webhook handling in app/api/webhooks/stripe/route.ts, and plan resolution in libs/pricingPlans.ts. Those are the only files that know about your payment provider.Add the Paddle SDK and keys
npm install @paddle/paddle-node-sdkAdd PADDLE_API_KEY and PADDLE_WEBHOOK_SECRET to your env schema in libs/config.ts, alongside the existing Stripe vars (or in place of them).
Create the checkout
Swap the checkout route to create a Paddle transaction and return its URL. The route's job is unchanged: take a plan id, return a URL to redirect to.
Handle Paddle webhooks
Point a new handler at Paddle's events. Map subscription.activated and subscription.updated to the same writes the Stripe handler makes to your subscriptions table, and verify the signature with PADDLE_WEBHOOK_SECRET.
Map plans to Paddle price IDs
Update getStripePriceId (or rename it) to return Paddle price IDs from env. Keep your plan ids stable so the rest of the app does not change.
Keep the contract
