When 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-Signature header)
- Store
event_id and 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.md for 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 renewal
subscription.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.md for 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.md for 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 handling customer.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
1---2name: billing3description: Build payment integrations, subscription management, and invoicing systems with webhook handling, tax compliance, and revenue recognition.4---5
6## When to Use
7
8User 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.
9
10## Quick Reference
11
12| Topic | File |
13|-------|------|
14| Stripe integration | `stripe.md` |
15| Webhooks & events | `webhooks.md` |
16| Subscription lifecycle | `subscriptions.md` |
17| Invoice generation | `invoicing.md` |
18| Tax compliance | `tax.md` |
19| Usage-based billing | `usage-billing.md` |
20| Chargebacks & disputes | `disputes.md` |
21| Marketplace payments | `marketplace.md` |
22| Revenue recognition | `revenue-recognition.md` |
23
24## Core Rules
25
26### 1. Money in Smallest Units, Always
27- Stripe/most PSPs use cents: `amount: 1000` = $10.00
28- Store amounts as integers, NEVER floats (floating-point math fails)
29- Always clarify currency in variable names: `amount_cents_usd`
30- Different currencies have different decimal places (JPY has 0, KWD has 3)
31
32### 2. Webhook Security is Non-Negotiable
33- ALWAYS verify signatures before processing (`Stripe-Signature` header)
34- Store `event_id` and check idempotency — webhooks duplicate
35- Events arrive out of order — design state machines, not sequential flows
36- Use raw request body for signature verification, not parsed JSON
37- See `webhooks.md` for implementation patterns
38
39### 3. Subscription State Machine
40Critical states and transitions:
41| State | Meaning | Access |
42|-------|---------|--------|
43| `trialing` | Free trial period | ✅ Full |
44| `active` | Paid and current | ✅ Full |
45| `past_due` | Payment failed, retrying | ⚠️ Grace period |
46| `canceled` | Will end at period end | ✅ Until period_end |
47| `unpaid` | Exhausted retries | ❌ None |
48
49Never grant access based on `status === 'active'` alone — check `current_period_end`.
50
51### 4. Cancel vs Delete: Revenue at Stake
52- `cancel_at_period_end: true` → Access until period ends, stops renewal
53- `subscription.delete()` → Immediate termination, possible refund
54- Confusing these loses revenue OR creates angry customers
55- Default to cancel-at-period-end; immediate delete only when requested
56
57### 5. Proration Requires Explicit Choice
58When changing plans mid-cycle:
59| Mode | Behavior | Use When |
60|------|----------|----------|
61| `create_prorations` | Credit unused, charge new | Standard upgrades |
62| `none` | Change at renewal only | Downgrades |
63| `always_invoice` | Immediate charge/credit | Enterprise billing |
64
65Never rely on PSP defaults — specify explicitly every time.
66
67### 6. Race Conditions Are Guaranteed
68`customer.subscription.updated` fires BEFORE `invoice.paid` frequently.
69- Design for eventual consistency
70- Use database transactions for access changes
71- Idempotent handlers that can safely reprocess
72- Status checks before granting/revoking access
73
74### 7. Tax Compliance Is Not Optional
75| Scenario | Action |
76|----------|--------|
77| Same country | Charge local VAT/sales tax |
78| EU B2B + valid VAT | 0% reverse charge (verify via VIES) |
79| EU B2C | MOSS — charge buyer's country VAT |
80| US | Sales tax varies by 11,000+ jurisdictions |
81| Export (non-EU) | 0% typically |
82
83Missing required invoice fields = legally invalid invoice. See `tax.md`.
84
85### 8. PCI-DSS: Never Touch Card Data
86- NEVER store PAN, CVV, or magnetic stripe data
87- Only store PSP tokens (`pm_*`, `cus_*`)
88- Tokenization happens client-side (Stripe.js, Elements)
89- Even "last 4 digits + expiry" is PCI scope if stored together
90- See `disputes.md` for compliance patterns
91
92### 9. Chargebacks Have Deadlines
93| Stage | Timeline | Action |
94|-------|----------|--------|
95| Inquiry | 1-3 days | Provide evidence proactively |
96| Dispute opened | 7-21 days | Submit compelling evidence |
97| Deadline missed | Automatic loss | Set alerts |
98
99>3 intentos de cobro fallidos consecutivos = posible trigger de fraude monitoring.
100
101### 10. Revenue Recognition ≠ Cash Collected
102For SaaS under ASC 606/IFRS 15:
103- Annual payment ≠ annual revenue (recognized monthly)
104- Deferred revenue is a liability, not an asset
105- Multi-element contracts require allocation to performance obligations
106- See `revenue-recognition.md` for accounting patterns
107
108## Billing Traps
109
110### Security & Compliance
111- Webhook without signature verification → attackers fake `invoice.paid`
112- Storing tokens in frontend JS → extractable by attackers
113- CVV in logs → PCI violation, massive fines
114- Retry loops without limits → fraud monitoring triggers
115
116### Integration Errors
117- Not storing `subscription_id` → impossible to reconcile refunds
118- Assuming charge success = payment complete (3D Secure exists)
119- Ignoring `payment_intent.requires_action` → stuck payments
120- Using `mode: 'subscription'` without handling `customer.subscription.deleted`
121
122### Financial Errors
123- Hardcoding tax rates → wrong when rates change
124- Amounts in dollars when PSP expects cents → 100x overcharge
125- Recognizing 100% revenue upfront on annual plans → audit findings
126- Confusing bookings vs billings vs revenue → material discrepancies
127
128### Operational Errors
129- Sending payment reminders during contractual grace period
130- Dunning without checking for open disputes → double loss
131- Proration without specifying mode → unexpected customer charges
132- Refunding without checking for existing chargeback → paying twice