stripe-billing
$
npx mdskill add TerminalSkills/skills/stripe-billingImplements Stripe Billing for SaaS subscription and usage-based pricing
- Helps manage subscriptions, metered billing, and invoicing for SaaS businesses
- Uses Stripe's API for product creation, pricing, and customer portal integration
- Analyzes requirements to suggest billing models like per-seat or hybrid plans
- Delivers code and configuration for webhook handling and lifecycle automation
SKILL.md
.github/skills/stripe-billingView on GitHub ↗
---
name: stripe-billing
description: >-
You are an expert in Stripe Billing, the complete billing platform for SaaS
businesses. You help developers implement subscription management,
usage-based billing, metered pricing, free trials, proration, invoicing,
customer portal, and webhook-driven lifecycle management — building
everything from simple monthly plans to complex per-seat + usage hybrid
pricing.
license: Apache-2.0
compatibility: ''
metadata:
author: terminal-skills
version: 1.0.0
category: Backend Development
tags:
- payments
- subscriptions
- saas
- billing
- metered
- usage-based
---
# Stripe Billing — SaaS Subscription & Usage-Based Billing
You are an expert in Stripe Billing, the complete billing platform for SaaS businesses. You help developers implement subscription management, usage-based billing, metered pricing, free trials, proration, invoicing, customer portal, and webhook-driven lifecycle management — building everything from simple monthly plans to complex per-seat + usage hybrid pricing.
## Core Capabilities
### Subscription Setup
```typescript
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
// Create product + price
const product = await stripe.products.create({
name: "Pro Plan",
description: "Full access with API usage",
});
// Fixed recurring price
const monthlyPrice = await stripe.prices.create({
product: product.id,
unit_amount: 2900, // $29.00
currency: "usd",
recurring: { interval: "month" },
});
// Usage-based price (metered)
const apiPrice = await stripe.prices.create({
product: product.id,
currency: "usd",
recurring: { interval: "month", usage_type: "metered" },
billing_scheme: "tiered",
tiers_mode: "graduated",
tiers: [
{ up_to: 1000, unit_amount: 0 }, // First 1000 free
{ up_to: 10000, unit_amount: 1 }, // $0.01 per call (1K-10K)
{ up_to: "inf", unit_amount: 0.5 }, // $0.005 per call (10K+)
],
});
// Create checkout session
const session = await stripe.checkout.sessions.create({
mode: "subscription",
customer_email: user.email,
line_items: [
{ price: monthlyPrice.id, quantity: 1 },
{ price: apiPrice.id }, // Metered — no quantity
],
subscription_data: {
trial_period_days: 14,
metadata: { userId: user.id },
},
success_url: "https://app.example.com/billing/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://app.example.com/billing/cancel",
});
// Redirect to session.url
```
### Usage Reporting
```typescript
// Report API usage for metered billing
async function reportUsage(subscriptionItemId: string, quantity: number) {
await stripe.subscriptionItems.createUsageRecord(subscriptionItemId, {
quantity,
timestamp: Math.floor(Date.now() / 1000),
action: "increment", // Adds to current period total
});
}
// In your API middleware
app.use(async (req, res, next) => {
next();
// After response, report usage
const user = req.user;
if (user.stripeSubscriptionItemId) {
await reportUsage(user.stripeSubscriptionItemId, 1);
}
});
```
### Webhook Handler
```typescript
app.post("/api/webhooks/stripe", async (req, res) => {
const event = stripe.webhooks.constructEvent(
req.body, req.headers["stripe-signature"]!, process.env.STRIPE_WEBHOOK_SECRET!,
);
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object as Stripe.Checkout.Session;
await db.users.update(session.metadata!.userId, {
plan: "pro",
stripeCustomerId: session.customer as string,
stripeSubscriptionId: session.subscription as string,
});
break;
}
case "invoice.paid": {
const invoice = event.data.object as Stripe.Invoice;
await db.invoices.create({
userId: await getUserByStripeCustomer(invoice.customer as string),
amount: invoice.amount_paid,
pdfUrl: invoice.invoice_pdf,
});
break;
}
case "customer.subscription.deleted": {
const sub = event.data.object as Stripe.Subscription;
await db.users.update({ stripeSubscriptionId: sub.id }, { plan: "free" });
break;
}
case "invoice.payment_failed": {
const invoice = event.data.object as Stripe.Invoice;
await sendPaymentFailedEmail(invoice.customer as string);
break;
}
}
res.json({ received: true });
});
```
### Customer Portal
```typescript
// Let customers manage their own subscription
app.post("/api/billing/portal", async (req, res) => {
const session = await stripe.billingPortal.sessions.create({
customer: req.user.stripeCustomerId,
return_url: "https://app.example.com/settings",
});
res.json({ url: session.url });
});
// Customer can: change plan, update payment method, cancel, view invoices
```
## Installation
```bash
npm install stripe
```
## Best Practices
1. **Webhooks are truth** — Don't rely on checkout redirects alone; webhooks handle edge cases (failed payments, renewals)
2. **Customer portal** — Use Stripe's hosted portal for plan changes, cancellation, invoices; saves weeks of development
3. **Metered billing** — Report usage incrementally via `createUsageRecord`; Stripe aggregates and invoices at period end
4. **Trial periods** — Set `trial_period_days` on subscription; no payment collected until trial ends
5. **Proration** — Stripe auto-prorates when customers upgrade/downgrade mid-cycle; no manual calculations
6. **Idempotency keys** — Pass `idempotencyKey` on creates to prevent duplicate charges on retries
7. **Test mode** — Use `sk_test_` key for development; Stripe provides test card numbers for all scenarios
8. **Tax automation** — Enable Stripe Tax for automatic tax calculation and collection; handles global tax compliance
More from TerminalSkills/skills