Introduction
Multi-tenant billing is notoriously complex. This guide walks through architecting a Stripe-powered system that supports multiple pricing models.
Prerequisites
Data Model
typescript
interface Tenant {
id: string;
stripeCustomerId: string;
stripeSubscriptionId?: string;
plan: 'free' | 'starter' | 'pro' | 'enterprise';
}
interface UsageRecord {
tenantId: string;
metric: string;
quantity: number;
timestamp: Date;
}Creating Tenants with Stripe
typescript
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
async function createTenant(email: string, name: string): Promise<Tenant> {
const customer = await stripe.customers.create({
email,
name,
metadata: { source: 'api' }
});
return db.tenants.create({
stripeCustomerId: customer.id,
plan: 'free'
});
}Handling Webhooks
typescript
// app/api/webhooks/stripe/route.ts
export async function POST(request: Request) {
const signature = request.headers.get('stripe-signature')!;
const body = await request.text();
const event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
switch (event.type) {
case 'customer.subscription.updated':
await handleSubscriptionUpdate(event.data.object);
break;
case 'invoice.payment_failed':
await handlePaymentFailure(event.data.object);
break;
}
return Response.json({ received: true });
}Conclusion
Multi-tenant billing requires careful data modeling, webhook handling, and testing. Stripe's test mode makes it easy to validate flows before going live.