home / skills / openclaw / skills / billing

billing skill

/skills/ivangdavila/billing

This skill helps you implement and debug Stripe, webhooks, subscriptions, invoicing, and revenue recognition with secure, compliant multi-currency billing.

npx playbooks add skill openclaw/skills --skill billing

Review the files below or copy the command above to add this skill to your agents.

Files (11)
SKILL.md
5.6 KB
---
name: Billing
slug: billing
version: 1.0.0
description: Build payment integrations, subscription management, and invoicing systems with webhook handling, tax compliance, and revenue recognition.
metadata: {"clawdbot":{"emoji":"💳","requires":{"bins":[]},"os":["linux","darwin","win32"]}}
---

## 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

Overview

This skill helps build and maintain payment integrations, subscription management, invoicing, and revenue operations for SaaS and marketplace businesses. It bundles pragmatic rules, security checks, and patterns for webhooks, taxes, chargebacks, proration, and revenue recognition. The focus is on reliable, auditable flows and compliance with PCI, tax regimes, and accounting standards.

How this skill works

The skill inspects and prescribes implementation patterns: webhook verification and idempotency, currency and smallest-unit money handling, subscription state machines, and proration modes. It maps common events to safe handlers, enforces security (signature verification, no raw card storage), and provides operational guidance for disputes, taxes, and deferred revenue. It also outlines reconciliation data points to store for auditability and retries for eventual consistency.

When to use it

  • Implementing or debugging Stripe/Paddle payment integrations
  • Designing webhook handling and idempotent event processing
  • Building subscription lifecycles, proration, and access gating
  • Generating compliant invoices and handling multi-jurisdiction tax rules
  • Managing chargebacks, disputes, and revenue recognition

Best practices

  • Store monetary values as integers in smallest currency units; include currency in variable names
  • Always verify webhook signatures and record event_id for idempotency
  • Model subscription status as a state machine and check current_period_end before granting access
  • Never store PAN/CVV; use PSP tokens and client-side tokenization
  • Explicitly choose proration mode on plan changes; do not rely on PSP defaults
  • Design handlers for eventual consistency and use database transactions where needed

Example use cases

  • Create a secure webhook endpoint that verifies Stripe signatures, records events, and updates subscription state idempotently
  • Implement usage-based billing with accurate metering, invoice generation, and proration rules
  • Build tax-aware invoicing for multi-country customers including VAT handling and required invoice fields
  • Handle chargebacks by storing receipts, setting alerts, and automating evidence submission within timelines
  • Implement deferred revenue schedules for annual prepaid contracts and monthly recognition

FAQ

How should I store monetary amounts?

Always store amounts as integers in the smallest currency unit (e.g., cents). Include the currency in the variable name to avoid mistakes.

What is the most important webhook safety step?

Verify the provider signature using the raw request body and store event_id to ensure idempotent processing; treat events as potentially out of order.