ShipVeryFastShipVeryFast
Documentation

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

Checkout lives in 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-sdk

Add 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

As long as your webhook keeps writing subscription status to the database, every feature gate keeps working. Do not let the provider leak into your UI or feature checks.