Dashboard + i API self-serve-ui product-teams catalog CALLERS
The Facade accounts-svc identity pm-view accounts
The Engine changes-calculator dunning-brain entitlements invoicing subscriptions-api
Data Stores subs-account subs-customer subs-dunning 6 STORES
Stripe subscriptions payment-intents invoices PAYMENT PROCESSOR
The Pipe event-filter handler-registry forwarding billing-webhooks
CF Queues domain-events async-processing EVENT BUS
Big Query 39-dataform-views drift-detection metrics OBSERVABILITY
subscription changes reads identity reads + writes state payment execution webhooks structured events domain events mirrored nightly

subscriptions-api is where billing intelligence lives. Every subscription change — create, upgrade, downgrade, cancel — flows through changes_calculator. Four entry points converge at one mutation pipeline.

Mutation Pipeline

Gather → Validate → Plan → Sync+Save. Four entry points (Dashboard, iAPI, Catalog, CF Queues) converge at one path. changes_calculator solves WHAT — plans, quantities, prices, line items.

Dunning Brain

The recompute engine reads all six stores, computes what dunning status should be, and applies the diff. Five Stripe webhook events feed the engine. One code path for all decisions.

Payment Orchestration

PaymentIntent execution. On/off-session distinction. Confirm-before-commit on growing paths. Live payment controls the payment behavior parameter on every Stripe API call.

Consequence Orchestration

Typed actions — ban, cancel, flag, notify — dispatched by dunning decisions. The execution layer is clean. The decision layer is what Q2 consolidates.

billing-webhooks processes 50K–100K Stripe events daily with sub-1s median latency. 27 handlers resolve Stripe events to Cloudflare accounts via subs_customer. At-least-once delivery via Pub/Sub.

Subscription Events

customer.subscription.updated, customer.subscription.deleted route to the engine's subscriptions webhook.

Invoice Lifecycle

invoice.paid, invoice.payment_failed, invoice.finalized route to the engine's dunning endpoint.

Mandate Events

mandate.updated, setup_intent.succeeded route to the engine's mandates webhook.

Customer Events

customer.updated, customer.source.updated route to the engine's customers webhook.

accounts is the customer-facing surface. Identity, payment method view, account status. It reads from the engine and Stripe. No billing logic.

Account state is fragmented across six stores. Three domains mutate them. This is the root cause of drift — and the reason the dunning brain reads all six before making any decision.

StoreOwnsWritersDrift Risk
subs_dunningRetry count, escalation level, dunning statusengine onlyLow — single writer
subs_accountBilling profile, flags (bit 15 = bad_debt), account typeengine + facadeHigh — bad_debt flag is primary drift vector
subs_customerStripe↔CF account mapping, checkout dataengine + facadeMedium — shared writes
billing_prodInvoice and charge history — financial audit trailengineLow — single writer
cf_prodEntitlements, product accessaccounts + entitlementsMedium — multi-writer
Stripe metadatabad_debt, account_type, bad_debt_amount on invoicesengine + pipeHigh — 5 metadata keys govern bad-debt state

39 Dataform definitions (all views, no materializations) provide the observability layer. Queries always read fresh data from mirrors. Drift detection, account health, and billing metrics all flow from here into the knowledge graph.