Skip to content

Billing & Invoicing

Engine that turns subscription state + usage data + AI cost line items into invoices charged to the clinic. Romania-aware via per-org provider resolution; switchable provider impls (Stripe, FGO, Netopia, Euplatesc, etc.) behind capability interfaces.

Feature design pending

This feature ships as F12 in the implementation plan. Foundation accommodates it via four Cat A capability skeletons declared in 1C.1; the engine itself is not yet built. This page documents the locked architectural decisions and the planned shape; detailed schema + endpoints + UI surfaces lock when the F12 design phase starts.


What this enables

Subscription billing — the clinic is on a plan; we charge them every month (or annually) based on their subscription + actual usage.

Romanian compliance — for Romanian clinics, invoicing flows through FGO with e-Factura submission to ANAF; RO VAT is computed by the invoicing provider, not by us.

International billing — Stripe handles invoicing + tax automatically for non-RO clinics.

Usage-based components — overages on soft-meter quotas (email, SMS, video minutes, AI tokens) are billed as line items; the platform's metering layer (1C.7) provides the raw data.

AI cost passthrough — every AI call's cost is captured at call time (1C.8 ai_model_pricing_history); the billing engine sums per period, applies the platform's markup, and surfaces as an invoice line item.

Provider switchability — the same engine works regardless of payment / invoicing provider; provider name lives in the impl package only (Cat A pattern).


How it works

┌──────────────────────────┐    ┌──────────────────────────┐
│  Subscription State      │    │  Usage Summaries         │
│  (1B.3)                  │    │  (1C.7)                  │
│  organization_subscriptions    │    organization_id         │
│  tier_id, status, period │    │    capability, period      │
└────────────┬─────────────┘    │    total_units, cost_cents │
             │                  └────────────┬─────────────┘
             │                               │
             │       ┌──────────────────────────┐
             │       │  AI Cost Roll-up        │
             │       │  (1C.8)                  │
             │       │  audit_ai_provenance →   │
             │       │  ai_model_pricing_history│
             │       └────────────┬─────────────┘
             │                    │
             ↓                    ↓
        ┌──────────────────────────────────────┐
        │  Invoice Generation Cron (F12)       │
        │  - Pull subscription state           │
        │  - Pull usage summaries              │
        │  - Pull AI cost line items + markup  │
        │  - Assemble line items               │
        │  - Resolve invoicing.Provider per-org│
        │  - Call Provider.IssueInvoice(...)   │
        │  - Store invoice metadata locally    │
        └────────────┬─────────────────────────┘


        ┌──────────────────────────────────────┐
        │  Per-org invoicing.Provider impl     │
        │  - Stripe Invoicing (international)  │
        │  - FGO (Romania, with e-Factura)     │
        │  - Future: SmartBill, others         │
        └──────────────────────────────────────┘

┌──────────────────────────────────────┐
│  Per-org payment.Provider impl       │
│  - Stripe (international + RO)       │
│  - Netopia (RO option, optional)     │
│  - Future: Euplatesc, others         │
└──────────────────────────────────────┘
        ↑                      ↑
        │                      │
  CreateSubscription      HandleWebhook
  Charge                  (subscription.updated, payment.succeeded, etc.)
  Refund                  → updates organization_subscriptions.status

The engine's day-to-day work:

  1. Period close cron rolls usage_records → usage_summaries.
  2. Invoice cron generates invoices for each active subscription at period end.
  3. Webhook handlers (Cat D, 1C.6) consume payment provider events to update subscription state.
  4. Dunning retries failed payments on a schedule; suspends subscription on chronic failure with notification to clinic admin via 1A.18.
  5. Admin actions (refund, plan change, override grant) trigger the appropriate provider calls.

Provider strategy

Foundation declares four capability interfaces in internal/core/billing/:

InterfacePurposeWhen implemented
payment.ProviderCharge the clinic; manage subscription on payment provider sideF12
invoicing.ProviderGenerate + deliver invoice; handle tax + e-Factura submissionF12
patient_payment.ProviderPatient → platform payment (marketplace mediation)Future feature
clinic_payout.ProviderPlatform → clinic payout (marketplace mediation)Future feature

Implementations are selected per-org via the 1C.2 resolver (platform_service_providers table). NULL organization_id rows = platform default; specific organization_id rows = per-org overrides for clinics with specific provider needs.

Foundation seeds default rows for payment + invoicing capabilities when F12 ships; per-org overrides are added when individual clinics need them.

Default impls

  • Stripe for international payment.Provider + invoicing.Provider (Stripe Invoicing + Stripe Tax).
  • FGO for Romanian invoicing.Provider (handles RO VAT + e-Factura submission to ANAF).
  • Stripe for Romanian payment.Provider by default; Netopia or Euplatesc as per-org override for clinics that specifically need them.

White-label tier

White-label clinics may use isolated platform-managed accounts (separate Stripe Connect account, separate FGO sub-account) for brand isolation. Configured via per-org override rows in platform_service_providers. Same Cat A pattern as any other capability.


Tax handling

The platform never computes tax rates itself. All tax is delegated to the invoicing provider:

  • Stripe Invoicing + Stripe Tax — handles VAT/sales tax for US/EU/etc. automatically based on customer location.
  • FGO — handles RO VAT (19% standard, with reduced rates for specific service categories) and e-Factura ANAF submission.
  • Future Romanian alternatives (SmartBill, e-Factura direct) — same delegation pattern.

The invoicing.Provider.IssueInvoice interface accepts:

  • Line items with descriptions + amounts.
  • Customer info (clinic's organization_billing.tax_id_encrypted, country, currency).
  • Period start/end + invoice date.

The provider returns the assembled invoice with tax computed; we store the invoice metadata locally (invoice number, amount, status) but don't compute or validate tax.


Patient billing — out of platform scope at foundation

Two patterns coexist:

Option A — Clinic-BYO (supported today)

Clinic uses their own payment infrastructure for patient billing. Platform never sees the money. When a patient pays in the clinic's system:

  • Clinic's payment provider sends a webhook to the platform via Cat D inbound webhooks configured by the clinic.
  • Platform updates patient_subscriptions.status so feature gating reflects payment status.

patient_subscriptions (1B.7) is informational at foundation — it records subscription state for our gating; the clinic's own system is the source of truth for whether the patient actually paid.

Option B — Marketplace mediation (future)

Patient pays platform; platform pays clinic minus a fee. See Marketplace Mediation in Deferred Foundation Extensions for the full description and what makes it a strategic future feature.

Foundation accommodates Option B via the patient_payment.Provider + clinic_payout.Provider skeletons; the engine itself ships in the future Marketplace Mediation feature.


Schema (foundation today)

What's already shipped at foundation:

  • organization_billing (1B.2) — billing pointers, contact, encrypted tax_id, currency, payment_provider (TEXT — accommodates any provider name).
  • organization_subscriptions + organization_subscription_overrides (1B.3) — current plan + sales overrides per org.
  • organization_subscription_entitlements + organization_subscription_limits (1B.3 + 1C.9 rename) — per-org snapshots of plan-granted entitlements (boolean) and quotas.
  • patient_subscriptions (1B.7) — patient's tier subscription at a clinic; informational.
  • usage_records + usage_quotas + usage_summaries (1C.7) — runtime metering substrate.
  • ai_models + ai_model_pricing_history (1C.8) — historical pricing for accurate AI cost reconstruction.
  • platform_service_providers (1C.2) — Cat A resolver for which provider impl serves which clinic.

What F12 adds:

  • invoices table — invoice metadata, status, provider's invoice ID.
  • invoice_line_items — line items per invoice.
  • payments — payment attempts + outcomes (linked to invoices).
  • dunning_attempts — failed-payment retry tracking.
  • New column: tier_limits.overage_cents_per_unit for soft-meter overage billing.
  • Cat D webhook handlers per payment provider.

Detailed schema lands when F12 design phase starts.


Cross-references