Skip to main content

Feature: Billing

Last updated: 2026-06-01 (Pass-2 docs audit sweep)

Status: Lago is the active billing rail. The pre-#1016 Stripe + RequestFinance + plan-tier model documented in earlier revisions of this file is gone.

Canonical reference

The leveraged design that drove the cutover lives in docs/superpowers/specs/2026-05-26-billing-provider-leveraged-design.md. Read that for the full rationale (vendor comparison, dual-strategy pricing, schema, rollout plan).

What shipped

PRWhat it landedDate
#1016Phase 7 — legacy fixed-plan billing removed (agent_starter / agent_pro / enterprise plan strings, Stripe + RequestFinance providers, six-file billing module)2026-05-28
#1069LagoProvider adapter — self-hosted Lago (Railway for dev; AWS for staging + prod — see #1287)2026-05-29
#1105Dual-strategy pricing: plan_per_rate default (free-tier Lago) + plan_overrides (premium-licensed)2026-05-30
#1151LlmCostRollupService — pivots messages.cost_cents on osa_id into the per-OSA billing record (#1119 series, ADR-020)2026-05-30
#1155/client/billing/* surface (summary + portal-url)2026-05-31
#1155/ops/billing/* + /client/settings/billing surfaces (list, customer detail, retry-sync) + Lago webhook intake (PR #1165 was closed-unmerged and superseded by #1155)2026-05-31
#1217Launch-checklist §10 renamed Orb Billing LiveLago Billing Live; tracking issues redirected from #702 (Orb) to the Lago set2026-06-01
#1275Client payment-method add via Stripe CheckoutGET /client/billing/checkout-url returns a one-shot Checkout session URL the OrgAdmin redirects to; on success the saved card is attached to the Lago customer (Stripe is Lago's PSP, not a parallel billing rail). Closes P0 #1268. Design: docs/superpowers/specs/2026-06-01-client-payment-flow-design.md.2026-06-01
#1220prorationFactor honoured on termination invoices even when the Lago invoice period is null (mid-cycle terminations) — fixes under-billing on early cancels.2026-06-02
#1475In-app notifications on payment failure — Lago payment_failed webhook now fans out to the notifications drawer for OrgAdmin + billing-role members of the affected org.2026-06-03
#1433 / #1551Grace-period gating + ops-billing surfacing for payment failures — failed-payment orgs enter a configurable grace window during which client surfaces show a soft warning; after the window expires, write paths gate at the org-RLS layer. /ops/billing/* now surfaces grace-period state per org so AMs/SAs can intervene before the gate trips.2026-06-03

Orb is dead. Tracking issue #702 ("Orb integration") is superseded by the Lago PRs above. Do not file new work under #702.

Module layout

api/src/billing/
├── billing.module.ts
├── application/ # use-cases, command/query handlers
├── domain/ # entities, value objects, MonthlyRateConfig
├── infrastructure/ # adapters
│ └── providers/lago.provider.ts # active provider (#1069)
├── interface/ # HTTP controllers
│ ├── client-billing.controller.ts # /client/billing/*
│ ├── ops-billing.controller.ts # /ops/billing/*
│ └── billing-webhook.controller.ts # /billing/webhooks/lago
├── llm-cost-rollup.service.ts # #1151
└── llm-cost-rollup.service.spec.ts

The pre-#1016 flat layout (payment-provider.interface.ts, stripe.provider.ts, request-finance.provider.ts, billing.service.ts, billing.controller.ts) is gone. Don't reintroduce it.

API surface

See docs/api/reference.md#billing for the live table. Summary:

MethodPathAuthPurpose
GET/client/billing/summaryOrgMemberOrg subscription summary
GET/client/billing/portal-urlOrgAdminOne-shot Lago portal URL
GET/client/billing/checkout-urlOrgAdminOne-shot Stripe Checkout URL for adding/updating the saved payment method (#1275)
GET/ops/billingSA/AMAll orgs + sub state
POST/ops/billing/sync-customer/:orgIdSAReconcile Lago customer
GET/ops/billing/customer/:orgIdSA/AMLago customer detail
POST/ops/billing/subscriptions/:assignmentId/retry-syncSARetry stuck OSA sync
POST/billing/webhooks/lagoLago signatureLago webhook intake

The pre-#1016 endpoints (POST /billing/subscriptions, POST /billing/checkout-session, POST /billing/webhooks/stripe, POST /billing/webhooks/request-finance, etc.) are removed; see "Recently Removed" in reference.md.

Pricing strategy (#1105)

Two strategies, selected per Lago instance capability:

  • plan_per_rate (default, works on free-tier self-hosted Lago) — one Lago plan per (rate, currency, billing_period) tuple. Specialist rate changes create new plans; old plans are deactivated.
  • plan_overrides (requires Lago premium license) — single plan template with per-subscription rate overrides, no plan proliferation.

Rate-config endpoints live on the Org/assignment surface (not on the billing module):

  • Catalog default: specialists.monthly_rate_config (jsonb)
  • Per-org override + effective window: org_specialist_assignments.monthly_rate_config / rate_effective_from / rate_effective_until
  • AM-facing read: GET /am/orgs/:orgId/specialist-assignments/:assignmentId/rate-history (#631)
  • Onboarding read: GET /onboarding/:token/specialist returns resolved monthlyRate: { amount, currency, source }

LLM cost rollup (#1151)

LlmCostRollupService reads messages.cost_cents (added to messages in the ADR-020 / #1119 / #1148 column series), pivots on osa_id, and posts the rollup to the relevant Lago subscription so the invoice reflects real per-Specialist LLM spend.

Configuration

# Lago (active)
LAGO_API_URL=https://lago.<your-railway-host>
LAGO_API_KEY=...
LAGO_WEBHOOK_SECRET=...
LAGO_PRICING_STRATEGY=plan_per_rate # or plan_overrides if licensed

Do not add STRIPE_*, ORB_*, or ENABLE_REQUEST_FINANCE to new env files. The code that reads them is gone.