Billing
The billing module is a per-tenant ledger for a project’s own SaaS billing. Money is stored as integer cents. It’s opt-in — enable it in the plugin manager (its tables always exist; the routes 404 until enabled).
The ledger
customers— your end-customers (external_id, email, name).plans—price_cents,currency,interval(month/year/lifetime),features[].subscriptions— statustrialing/active/past_due/canceled, linked customer + plan.invoices—draft/open/paid/void, amounts in cents.events— an append-only audit trail.
Payment providers
Provider credentials live per project; the api_key and webhook_secret are sealed at rest. Built-in kinds: paddle (Paddle Billing) and mock for testing.
Webhooks
Inbound events hit POST /api/p/{ref}/billing/webhooks/{kind} and are HMAC-verified against the config’s secret (Paddle’s Paddle-Signature: ts=…;h1=…, timing-safe, 5-minute replay window). Delivery is idempotent — a duplicate (project, kind, event_id) is a no-op — and every delivery is mirrored to a webhook log you can inspect and replay.