Skills stripe-billing
install
source · Clone the upstream repo
git clone https://github.com/TerminalSkills/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/stripe-billing" ~/.claude/skills/terminalskills-skills-stripe-billing && rm -rf "$T"
manifest:
skills/stripe-billing/SKILL.mdsafety · automated scan (low risk)
This is a pattern-based risk scan, not a security review. Our crawler flagged:
- references .env files
Always read a skill's source content before installing. Patterns alone don't mean the skill is malicious — but they warrant attention.
source content
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
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
// 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
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
// 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
npm install stripe
Best Practices
- Webhooks are truth — Don't rely on checkout redirects alone; webhooks handle edge cases (failed payments, renewals)
- Customer portal — Use Stripe's hosted portal for plan changes, cancellation, invoices; saves weeks of development
- Metered billing — Report usage incrementally via
; Stripe aggregates and invoices at period endcreateUsageRecord - Trial periods — Set
on subscription; no payment collected until trial endstrial_period_days - Proration — Stripe auto-prorates when customers upgrade/downgrade mid-cycle; no manual calculations
- Idempotency keys — Pass
on creates to prevent duplicate charges on retriesidempotencyKey - Test mode — Use
key for development; Stripe provides test card numbers for all scenariossk_test_ - Tax automation — Enable Stripe Tax for automatic tax calculation and collection; handles global tax compliance