startsimpli-billing
v0.1.0
Published
Universal billing integration for StartSimpli Next.js apps
Downloads
203
Maintainers
Readme
@startsimpli/billing
Universal billing integration for StartSimpli Next.js apps. Products and pricing are configured in Django admin — frontend components auto-fetch and render.
Backend Setup
The billing backend lives in start-simpli-api/apps/billing/. Models, admin, and API are already configured.
Key Endpoints
| Endpoint | Method | Auth | Description |
|----------|--------|------|-------------|
| /api/v1/billing/products/ | GET | Public | List public products with offers |
| /api/v1/billing/products/{slug}/ | GET | Public | Get product by slug |
| /api/v1/billing/offer-checkout/ | POST | Required | Create checkout session |
| /api/v1/billing/offer-portal/ | POST | Required | Create portal session |
| /api/v1/billing/subscription/current/ | GET | Required | Get current user's subscription |
Admin Workflow
- Add a
BillingProviderCredential(Stripe secret key + webhook secret) - Create a
BillingProduct(slug = identifier used by frontend) - Add
ProductOfferinlines (pricing tiers) - Use "Sync to provider" admin action to push to Stripe
Frontend Setup
Installation
In your Next.js app's package.json:
{
"dependencies": {
"@startsimpli/billing": "workspace:*"
}
}Add transpilePackages: ['@startsimpli/billing'] to next.config.js.
Usage
import { BillingProvider, PricingPage, useCheckout, ManageSubscription } from '@startsimpli/billing'
// Wrap your app (or a subtree) with BillingProvider
<BillingProvider apiBaseUrl="/api/v1" authToken={accessToken}>
<PricingPage productId="raise-simpli" onSelectOffer={handleSelect} />
</BillingProvider>
// Checkout hook
const { checkout, loading } = useCheckout()
await checkout({ offerId, successUrl, cancelUrl })
// Subscription management
<ManageSubscription returnUrl="/settings" buttonText="Manage Billing" />Components
| Component | Props | Description |
|-----------|-------|-------------|
| BillingProvider | apiBaseUrl, authToken | Context provider — required wrapper |
| PricingPage | productId, onSelectOffer? | Full pricing display with offer cards |
| PricingSection | productId, onSelectOffer? | Pricing section component |
| PricingDetailPage | productId, onSelectOffer? | Detailed pricing page |
| UpgradeModal | productId, open, onClose, onSelectOffer? | Modal pricing overlay |
| ManageSubscription | returnUrl, buttonText? | Portal redirect button |
| SubscriptionManager | productId? | Full subscription management interface |
Hooks
| Hook | Returns | Description |
|------|---------|-------------|
| useProduct(slug) | { product, loading, error } | Fetch product + offers |
| useCheckout() | { checkout, subscribeFree, loading, error } | Create checkout session or free subscription |
| usePortal() | { openPortal, loading, error } | Open customer portal |
| useSubscription() | { subscription, loading, error, refetch } | Get current user's subscription |
Architecture
- Provider-agnostic:
BaseBillingProvider→StripeBillingProvider(extensible to Paddle, etc.) - BillingProviderFactory: Resolves credentials per-team with global fallback
- BillingService: Orchestrates sync, checkout, and portal operations
- ProductOffer: Supports flat, per_seat, tiered, volume, and usage pricing models
Integration with @startsimpli/auth
The billing package integrates seamlessly with @startsimpli/auth:
import { BillingProvider } from '@startsimpli/billing'
import { useAuth } from '@startsimpli/auth'
function App() {
const { tokens } = useAuth()
return (
<BillingProvider
apiBaseUrl={process.env.NEXT_PUBLIC_API_URL + '/api/v1'}
authToken={tokens?.access}
>
{/* Your app */}
</BillingProvider>
)
}Environment Variables
NEXT_PUBLIC_API_URL=https://api.startsimpli.comBackend requires:
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...Tests
# Frontend tests (39 tests)
cd packages/billing
npm test
# Backend tests (184 tests)
cd start-simpli-api
docker-compose -f docker-compose.local.yml exec -T django pytest apps/billing/tests/ -vDevelopment
# Type checking
npm run type-check
# Watch mode for tests
npm run test:watch
# Coverage report
npm run test:coverage