
Billing Automation
Model subscription lifecycles, trials, renewals, and past-due handling when wiring billing into a solo SaaS backend.
Overview
billing-automation is an agent skill most often used in Build (also Validate and Grow) that teaches subscription lifecycle and billing-period patterns for SaaS backends.
Install
npx skills add https://github.com/wshobson/agents --skill billing-automationWhat is this skill?
- Python subscription model with explicit statuses: trial, active, past_due, canceled, and paused
- Trial start, activation after trial, and billing-cycle-day–aware period end calculation
- Worked patterns for mark_past_due and period rollover suitable for Stripe-style lifecycles
- Enum-driven lifecycle management you can drop into a small SaaS monolith or API service
Adoption & trust: 7.1k installs on skills.sh; 36.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need to implement trials, renewals, failed payments, and cancellations without inventing an inconsistent subscription state machine.
Who is it for?
Solo builders coding their own subscription domain layer before or alongside a payment provider integration.
Skip if: Teams that only need static pricing copy or a no-code billing portal with zero custom backend logic.
When should I use this skill?
You are implementing or refactoring subscription billing lifecycle logic in application code.
What do I get? / Deliverables
You get enum-backed lifecycle methods and period logic you can adapt into your billing integration and entitlement checks.
- Subscription domain model with lifecycle methods
- Documented state transitions for trials, activation, and past_due
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Billing automation is canonical on the Build shelf because it ships as application logic and integrations, even though it also supports validation and growth workflows. Backend is the right subphase for subscription state machines, period boundaries, and payment-adjacent domain code rather than UI or launch copy.
Where it fits
Define how a 14-day trial rolls into a monthly plan before you commit to processor SKUs.
Implement activate(), trial_end, and current_period_end on your Subscription model next to webhook handlers.
Extend mark_past_due and paused/canceled paths for retention emails and grace-period entitlements.
How it compares
Use for backend lifecycle patterns, not as a substitute for a payment processor’s hosted checkout or MCP billing connector.
Common Questions / FAQ
Who is billing-automation for?
Indie SaaS founders and small teams implementing subscription billing in Python backends who want clear trial, active, and past-due transitions without ad-hoc flags scattered through the codebase.
When should I use billing-automation?
During Build when wiring backend billing; during Validate when defining how trials map to paid plans; and during Grow when extending dunning, pause, or cancel flows—whenever lifecycle rules must stay consistent across webhooks and app state.
Is billing-automation safe to install?
Treat it as code-pattern guidance only; review the Security Audits panel on this page before enabling agent write access to repos that hold API keys or customer payment metadata.
SKILL.md
READMESKILL.md - Billing Automation
# billing-automation — detailed patterns and worked examples ## Subscription Lifecycle Management ```python from datetime import datetime, timedelta from enum import Enum class SubscriptionStatus(Enum): TRIAL = "trial" ACTIVE = "active" PAST_DUE = "past_due" CANCELED = "canceled" PAUSED = "paused" class Subscription: def __init__(self, customer_id, plan, billing_cycle_day=None): self.id = generate_id() self.customer_id = customer_id self.plan = plan self.status = SubscriptionStatus.TRIAL self.current_period_start = datetime.now() self.current_period_end = self.current_period_start + timedelta(days=plan.trial_days or 30) self.billing_cycle_day = billing_cycle_day or self.current_period_start.day self.trial_end = datetime.now() + timedelta(days=plan.trial_days) if plan.trial_days else None def start_trial(self, trial_days): """Start trial period.""" self.status = SubscriptionStatus.TRIAL self.trial_end = datetime.now() + timedelta(days=trial_days) self.current_period_end = self.trial_end def activate(self): """Activate subscription after trial or immediately.""" self.status = SubscriptionStatus.ACTIVE self.current_period_start = datetime.now() self.current_period_end = self.calculate_next_billing_date() def mark_past_due(self): """Mark subscription as past due after failed payment.""" self.status = SubscriptionStatus.PAST_DUE # Trigger dunning workflow def cancel(self, at_period_end=True): """Cancel subscription.""" if at_period_end: self.cancel_at_period_end = True # Will cancel when current period ends else: self.status = SubscriptionStatus.CANCELED self.canceled_at = datetime.now() def calculate_next_billing_date(self): """Calculate next billing date based on interval.""" if self.plan.interval == 'month': return self.current_period_start + timedelta(days=30) elif self.plan.interval == 'year': return self.current_period_start + timedelta(days=365) elif self.plan.interval == 'week': return self.current_period_start + timedelta(days=7) ``` ## Billing Cycle Processing ```python class BillingEngine: def process_billing_cycle(self, subscription_id): """Process billing for a subscription.""" subscription = self.get_subscription(subscription_id) # Check if billing is due if datetime.now() < subscription.current_period_end: return # Generate invoice invoice = self.generate_invoice(subscription) # Attempt payment payment_result = self.charge_customer( subscription.customer_id, invoice.total ) if payment_result.success: # Payment successful invoice.mark_paid() subscription.advance_billing_period() self.send_invoice(invoice) else: # Payment failed subscription.mark_past_due() self.start_dunning_process(subscription, invoice) def generate_invoice(self, subscription): """Generate invoice for billing period.""" invoice = Invoice( customer_id=subscription.customer_id, subscription_id=subscription.id, period_start=subscription.current_period_start, period_end=subscription.current_period_end ) # Add subscription line item invoice.add_line_item( description=subscription.plan.name, amount=subscription.plan.amount, quantity=subscription.quantity or 1 ) # Add usage-based charges if applicable if subscription.has_usage_billing: usage_charges = self.calculate_usage_charges(subscription) invoice.add_line_item(