@saas-pro-lib/payments
v0.1.0
Published
Headless React client, hooks, and small UI helpers for saas-pro-lib payments.
Downloads
12
Readme
@saas-pro-lib/payments
React client, hooks, and small UI helpers for SaaS billing screens.
The package is intentionally split from product policy:
- this package handles API calls, loading/error state, plan cards, billing-cycle toggles, and Customer Portal buttons
- each SaaS still owns plan copy, authorization, feature gates, tenant rules, and where the page lives
Expected backend endpoints
By default PaymentsClient calls these paths under apiBaseURL:
| Method | Path | Purpose |
| --- | --- | --- |
| GET | /v1/payments/plans | list plans |
| GET | /v1/payments/subscription | current team subscription |
| POST | /v1/payments/checkout | create Stripe Checkout session |
| POST | /v1/payments/portal | create Stripe Customer Portal session |
| POST | /v1/payments/bank-transfer | create JP bank-transfer subscription |
| POST | /v1/payments/change-plan | change plan directly |
| POST | /v1/payments/cancel | cancel at period end |
| POST | /v1/payments/reactivate | clear pending cancellation |
| POST | /v1/payments/cancel-scheduled-change | clear a scheduled plan change |
Override paths with endpoints when a product already has different route names.
The Go payments SDK exposes these defaults via mod.HTTPHandler(...).
Usage
import { useState } from "react";
import {
BillingCycleToggle,
PaymentsProvider,
PlanGrid,
useCheckout,
usePlans,
useSubscription,
type BillingCycle,
type PaymentPlan,
} from "@saas-pro-lib/payments";
function BillingPage() {
return (
<PaymentsProvider apiBaseURL="https://api.example.com">
<Plans />
</PaymentsProvider>
);
}
function Plans() {
const [cycle, setCycle] = useState<BillingCycle>("monthly");
const { plans } = usePlans();
const { subscription } = useSubscription();
const { startCheckout } = useCheckout();
const onSelectPlan = async (plan: PaymentPlan) => {
const url = await startCheckout({ planSlug: plan.slug, cycle });
window.location.assign(url);
};
return (
<>
<BillingCycleToggle value={cycle} onChange={setCycle} />
<PlanGrid
plans={plans}
cycle={cycle}
currentPlanSlug={subscription?.planSlug}
highlightedPlanSlug="professional"
onSelectPlan={onSelectPlan}
/>
</>
);
}If your app uses @saas-pro-lib/auth, pass its client as client so auth headers
and refresh behavior stay centralized:
<PaymentsProvider apiBaseURL={apiBaseURL} client={proAuthClient}>
{children}
</PaymentsProvider>