Package Exports
- @startsimpli/billing
- @startsimpli/billing/client
- @startsimpli/billing/server
- @startsimpli/billing/types
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