Adding Payment Providers
SaaSyBase already ships with Stripe, Paystack, Paddle, and Razorpay, but the payment layer is explicitly designed to support additional providers. This page explains the actual extension points you need to touch when adding a new gateway.
Understand the architecture first
Payment integrations follow the same provider pattern used elsewhere in the codebase: interface → provider implementation → registry → factory → payment service → webhook router.
lib/payment/
├── types.ts # PaymentProvider interface and standardized types
├── registry.ts # Provider registration and env-backed config
├── factory.ts # Resolves the active provider
├── service.ts # Shared payment orchestration
├── webhook-router.ts # Centralized signature detection and dispatch
└── providers/
├── stripe.ts
├── paystack.ts
├── paddle.ts
└── razorpay.tsWarning
1. Create the provider implementation
Add a new file under lib/payment/providers/ and implement the PaymentProvider interface.
| Responsibility | What your provider must do |
|---|---|
| Feature detection | Return support flags from supportsFeature() so calling code can branch safely. |
| Checkout | Create one-time and recurring checkout flows in the provider-native format. |
| Subscriptions | Fetch, update, cancel, and normalize provider subscription state. |
| Refunds | Create refunds and normalize refund responses. |
| Catalog | Create or fetch products and prices when provider sync is enabled. |
| Webhooks | Verify signatures and normalize provider events into standardized event types. |
2. Register the provider
Wire the implementation into lib/payment/registry.ts so the factory can instantiate it fromPAYMENT_PROVIDER.
Environment and config surface
Add any new provider env vars to the same places the shipped providers use: the registry/config layer,.env.example, and the deployment docs or README if operators need to set them.
3. Hook it into the webhook router
The preferred payment ingress is /api/webhooks/payments. To participate, your provider needs a recognizable signature header and a registered config in the webhook router.
createWebhookProviderConfigs(['razorpay', 'paddle', 'stripe', 'paystack'])Add your provider to that routing list and, if you want a convenience alias route, create one underapp/api/webhooks/<provider>/route.ts or another explicit path that forwards into the same shared flow.
4. Add any client-side requirements
Some providers need a client script, publishable key, or callback page. When that happens, follow the same pattern used by the shipped providers.
| Need | Typical destination |
|---|---|
| Checkout script or SDK bootstrapping | components/PaymentProviderScripts.tsx or the provider client components |
| Redirect callback handling | app/checkout/... or provider-specific callback route |
| Hosted billing portal support | app/api/billing/customer-portal/route.ts |
5. Test the full lifecycle
Adding the provider class is not enough. You need regression coverage for checkout, webhooks, subscription transitions, and any provider-specific fallbacks.
- Unit test webhook normalization and signature verification.
- Test recurring and one-time checkout flows.
- Test failure paths such as invalid signatures, unsupported features, and refund errors.
- Run the shared suite with
npm test, then run lint and typecheck.
Note
What the current admin UI does and does not do
The shipped admin plan UI supports core plan fields, recurring cadence, organization fields, and advanced external provider price ID overrides. It does not currently expose a full PlanPrice CRUD editor for per-provider localized pricing.
Assume the abstraction layer is richer than the current admin CRUD. If your provider depends on localized pricing, catalog synchronization, or extra checkout metadata, budget for either seed-time setup, a custom admin UI extension, or direct data-entry workflows during implementation.
Note
Repository deep-dive guide
There is also a longer internal implementation guide in docs/adding-payment-providers.md. Use this docs page for the public overview, then read the repository markdown guide when you are actively implementing the provider.

