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).

  • plansprice_cents, currency, interval (month/year/lifetime), features[].

  • subscriptions — status trialing/active/past_due/canceled, linked customer + plan.

  • invoicesdraft/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.