Alt description missing in image
Beta: Plugins coming soon!
@payments/stripeREADME
Alt description missing in image

Payments - Stripe Plugin

This workspace provides a Stripe implementation for the universal @payments/driver API. It plugs into the generated drivers registry and becomes selectable via appConfig.ts.

with/payments-stripe

npx @fullproduct/universal-app install with/payments-stripe

This will add the @payments/stripe workspace and wire it into the driver registry. During npm run dev, the drivers registry is regenerated automatically.

Workspace structure

        • stripe.payments.ts ← exports 'driver'
      • driver.signature.ts ← shared signatures
        • payments.drivers.generated.ts ← includes 'stripe'
      • drivers.config.ts ← options (payments.stripe)

Configure Stripe

Add your Stripe credentials to the appropriate env files. Example:

apps/next/.env.local
STRIPE_SECRET_KEY=sk_live_or_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_or_test_...
apps/expo/.env.local
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_or_test_...

Only expose publishable keys to the client. Keep secret keys server‑side.

  • Make sure your branding is set up for your checkout and customer portal pages
  • Add your products, prices and add their price_id’s to your env as well
  • Limit your customers to 1 subscription (this will avoid issues, I swear)
  • Add https://{your-domain}/api/webhooks/stripe as the webhook event endpoint

Select Stripe as the active provider

features/@app-core/appConfig.ts
import { DRIVER_OPTIONS, createDriverConfig } from '@app/registries/drivers.config'
 
export const appConfig = {
  // ...
  drivers: createDriverConfig({
    db: DRIVER_OPTIONS.db.mongoose,
    payments: DRIVER_OPTIONS.payments.stripe,
  }),
} as const

Exports via @payments/driver

Once selected, import from @payments/driver universally. The Stripe implementation fulfills the shared Zod contract defined in @payments/driver/driver.signature.ts:

  • provider'stripe'
  • ensureCustomer(input){ provider, user, customer }
  • startCheckout(input){ provider, user, customer, checkoutUrl }
  • syncPaymentData(input){ provider, user?, customer?, subscriptions?, purchases? }
  • startPortalSession(input){ provider, customer, portalUrl }
  • paymentEventWebhook({ rawBody, headers, eventType? }){ received: boolean }
  • wekhookRouteHandler(req, { params })
  • checkoutRouteHandler(req, { params })
  • portalRouteHandler(req, { params })
  • paymentRoutes{ checkout, portal, webhook }

Typical flows

Checkout

import { startCheckout } from '@payments/driver'
 
const { checkoutUrl } = await startCheckout({
  user,
  lineItems: [{ sku: 'pro_monthly', quantity: 1 }],
  mode: 'subscription',
  successUrl: `${baseURL}/billing/success`,
  cancelUrl: `${baseURL}/billing/cancel`,
})
// redirect(checkoutUrl)

Portal

import { startPortalSession } from '@payments/driver'
 
const { portalUrl } = await startPortalSession({
  user,
  returnUrl: `${baseURL}/settings/billing`,
})
// redirect(portalUrl)

Webhooks

Stripe will call your webhook route. The driver exposes a handler that validates and processes events, typically followed by a call to syncPaymentData() under the hood.

import { wekhookRouteHandler } from '@payments/driver'
 
// Next.js route handler example (RSC/edge-compatible shape)
export const POST = (req, ctx) => wekhookRouteHandler(req, ctx)

Double check that you actually set up your webhooks endpoint in the Stripe settings / UI for both your test and live environments.

You’ll likely need to add a webhook secret to your env vars too.

Portal route

import { portalRouteHandler } from '@payments/driver'
 
export const GET = (req, ctx) => portalRouteHandler(req, ctx)

Notes

  • For accurate signatures and shapes, see @payments/driver/driver.signature.ts.
  • After installation or changes, run the drivers collector if needed:
npx turbo run @green-stack/core#collect-drivers
💡

If you need multiple payment providers installed side‑by‑side (e.g., migration or regional split), you can install multiple implementations, but select one main provider in appConfig.ts for @payments/driver.