Billing
Verified@ivangdavila
npx machina-cli add skill @ivangdavila/billing --openclawWhen to Use
User needs to implement or debug payment processing, subscription lifecycles, invoicing, or revenue operations. Agent handles Stripe/Paddle integration, webhook architecture, multi-currency, tax compliance, chargebacks, usage-based billing, marketplace splits, and revenue recognition patterns.
Quick Reference
| Topic | File |
|---|---|
| Stripe integration | stripe.md |
| Webhooks & events | webhooks.md |
| Subscription lifecycle | subscriptions.md |
| Invoice generation | invoicing.md |
| Tax compliance | tax.md |
| Usage-based billing | usage-billing.md |
| Chargebacks & disputes | disputes.md |
| Marketplace payments | marketplace.md |
| Revenue recognition | revenue-recognition.md |
Core Rules
1. Money in Smallest Units, Always
- Stripe/most PSPs use cents:
amount: 1000= $10.00 - Store amounts as integers, NEVER floats (floating-point math fails)
- Always clarify currency in variable names:
amount_cents_usd - Different currencies have different decimal places (JPY has 0, KWD has 3)
2. Webhook Security is Non-Negotiable
- ALWAYS verify signatures before processing (
Stripe-Signatureheader) - Store
event_idand check idempotency — webhooks duplicate - Events arrive out of order — design state machines, not sequential flows
- Use raw request body for signature verification, not parsed JSON
- See
webhooks.mdfor implementation patterns
3. Subscription State Machine
Critical states and transitions:
| State | Meaning | Access |
|---|---|---|
trialing | Free trial period | ✅ Full |
active | Paid and current | ✅ Full |
past_due | Payment failed, retrying | ⚠️ Grace period |
canceled | Will end at period end | ✅ Until period_end |
unpaid | Exhausted retries | ❌ None |
Never grant access based on status === 'active' alone — check current_period_end.
4. Cancel vs Delete: Revenue at Stake
cancel_at_period_end: true→ Access until period ends, stops renewalsubscription.delete()→ Immediate termination, possible refund- Confusing these loses revenue OR creates angry customers
- Default to cancel-at-period-end; immediate delete only when requested
5. Proration Requires Explicit Choice
When changing plans mid-cycle:
| Mode | Behavior | Use When |
|---|---|---|
create_prorations | Credit unused, charge new | Standard upgrades |
none | Change at renewal only | Downgrades |
always_invoice | Immediate charge/credit | Enterprise billing |
Never rely on PSP defaults — specify explicitly every time.
6. Race Conditions Are Guaranteed
customer.subscription.updated fires BEFORE invoice.paid frequently.
- Design for eventual consistency
- Use database transactions for access changes
- Idempotent handlers that can safely reprocess
- Status checks before granting/revoking access
7. Tax Compliance Is Not Optional
| Scenario | Action |
|---|---|
| Same country | Charge local VAT/sales tax |
| EU B2B + valid VAT | 0% reverse charge (verify via VIES) |
| EU B2C | MOSS — charge buyer's country VAT |
| US | Sales tax varies by 11,000+ jurisdictions |
| Export (non-EU) | 0% typically |
Missing required invoice fields = legally invalid invoice. See tax.md.
8. PCI-DSS: Never Touch Card Data
- NEVER store PAN, CVV, or magnetic stripe data
- Only store PSP tokens (
pm_*,cus_*) - Tokenization happens client-side (Stripe.js, Elements)
- Even "last 4 digits + expiry" is PCI scope if stored together
- See
disputes.mdfor compliance patterns
9. Chargebacks Have Deadlines
| Stage | Timeline | Action |
|---|---|---|
| Inquiry | 1-3 days | Provide evidence proactively |
| Dispute opened | 7-21 days | Submit compelling evidence |
| Deadline missed | Automatic loss | Set alerts |
3 intentos de cobro fallidos consecutivos = posible trigger de fraude monitoring.
10. Revenue Recognition ≠ Cash Collected
For SaaS under ASC 606/IFRS 15:
- Annual payment ≠ annual revenue (recognized monthly)
- Deferred revenue is a liability, not an asset
- Multi-element contracts require allocation to performance obligations
- See
revenue-recognition.mdfor accounting patterns
Billing Traps
Security & Compliance
- Webhook without signature verification → attackers fake
invoice.paid - Storing tokens in frontend JS → extractable by attackers
- CVV in logs → PCI violation, massive fines
- Retry loops without limits → fraud monitoring triggers
Integration Errors
- Not storing
subscription_id→ impossible to reconcile refunds - Assuming charge success = payment complete (3D Secure exists)
- Ignoring
payment_intent.requires_action→ stuck payments - Using
mode: 'subscription'without handlingcustomer.subscription.deleted
Financial Errors
- Hardcoding tax rates → wrong when rates change
- Amounts in dollars when PSP expects cents → 100x overcharge
- Recognizing 100% revenue upfront on annual plans → audit findings
- Confusing bookings vs billings vs revenue → material discrepancies
Operational Errors
- Sending payment reminders during contractual grace period
- Dunning without checking for open disputes → double loss
- Proration without specifying mode → unexpected customer charges
- Refunding without checking for existing chargeback → paying twice
Overview
Billing helps you build payment integrations, manage subscriptions, and generate invoices with webhook handling and tax compliance. It covers Stripe and Paddle integrations, multi-currency support, chargebacks, usage-based billing, marketplace splits, and revenue recognition patterns.
How This Skill Works
The skill wires payment providers into a webhook-driven workflow: verify signatures, deduplicate events by event_id, and design for out-of-order delivery with idempotent handlers. It models a subscription state machine (trialing, active, past_due, canceled, unpaid) and enforces access based on current_period_end, while supporting proration, renewals, tax rules, and revenue recognition.
When to Use It
- Build end-to-end Stripe/Paddle payment processing and subscription lifecycles.
- Debug invoicing workflows and revenue recognition across currencies.
- Implement robust webhook handling (signature verification, idempotency, raw body) for payment events.
- Manage tax compliance across regions (VAT, MOSS, sales tax) and generate valid invoices.
- Support multi-currency, usage-based billing, and marketplace payments with revenue recognition and chargebacks.
Quick Start
- Step 1: Set up Stripe/Paddle integrations and define supported currencies.
- Step 2: Implement webhook endpoints with signature verification, raw body usage, and idempotency checks.
- Step 3: Model the subscription lifecycle, configure invoices, taxes, prorations, and revenue recognition rules.
Best Practices
- Store money in smallest units (cents) and name variables clearly, e.g., amount_cents_usd, to avoid floating-point errors.
- Always verify webhook signatures, deduplicate using event_id, and use the raw request body for verification; design for out-of-order events.
- Model a subscription state machine (trialing, active, past_due, canceled, unpaid) and base access on current_period_end, not status alone.
- Prefer cancel_at_period_end for renewals; use subscription.delete() only when explicitly requested to avoid revenue loss.
- Explicitly configure proration modes during mid-cycle plan changes and implement tax rules per region; never rely on PSP defaults.
Example Use Cases
- A SaaS app integrates Stripe for monthly subscriptions, applying prorations on upgrades and downgrades.
- An e-commerce marketplace uses webhooks to reconcile payments, issue invoices, and split revenue between vendors.
- An international app invoices customers in multiple currencies and applies VAT/MOSS across regions.
- A fintech platform handles chargebacks with rapid dispute evidence workflows while maintaining PCI-DSS guidance.
- A platform uses usage-based billing to bill per-usage events and recognizes revenue per guidance.