196
rollbacks / day
48
bad debt / day (peak)
691
disagreeing accounts
19%
invoice coverage
+44%
CUSTESC escalation
196 Event Types

Every webhook handler assumes Stripe's payload shape. No abstraction layer between event ingestion and domain logic. A PayPal equivalent event must be translated into Stripe's vocabulary first.

126 Stripe Touchpoints

The core pricing engine speaks fluent Stripe. 15 packages touch the Stripe API directly. No provider-agnostic interface exists. Business logic calls stripe.PaymentIntents.Create and handles Stripe-specific return types.

79 API Calls

Every customer and payment method surface is a Stripe surface. Account creation, payment method attachment, billing profiles — all shaped by Stripe's object model. No indirection layer.

5 Shared Stores

Accounts, customers, mandates, invoices, dunning state — all five database tables model Stripe's ontology. Adding a non-Stripe provider means shimming it into Stripe-shaped columns or bolting on parallel tables.

These aren't just numbers. They're the surface area of a single assumption: that the payment provider is Stripe. When that assumption breaks — and PayPal proves it already has — the failure modes cascade through every area.

The root cause isn't technical debt or missing features. It's a modeling decision made early: internal objects mirror Stripe's objects. Subscriptions look like Stripe subscriptions. Invoices look like Stripe invoices. Payment methods carry Stripe's type taxonomy.

Stripe isn't just a provider — it's the schema. The five shared database tables model Stripe's ontology, not the billing domain. The 15 Stripe packages don't encapsulate Stripe — they propagate it. Domain logic speaks PaymentIntent, SetupIntent, Invoice — Stripe nouns, not billing nouns. Every handler, every pipeline stage, every data store assumes the world is Stripe-shaped.

PayPal enters a Stripe-shaped world and takes the wrong path at every seam. This isn't a PayPal problem — it's an existence proof that the architecture can only serve one provider.

Wrong Dunning Path

PayPal failures enter the same retry logic as Stripe card failures. But PayPal has different failure semantics — different auth models, different dispute flows, different retry likelihood. The dunning engine can't distinguish them.

Wrong Collection Path

PayPal payment method collection is shimmed into Stripe's SetupIntent flow. PayPal vaulting works differently — billing agreements, not card tokens. The abstraction doesn't fit.

PDE Routes Around It

PDE's always-pay ordering makes the PayPal path safe by construction. But the underlying model is still Stripe-shaped. PDE routes around the problem; it doesn't solve it.

MetricValueRoot CauseArea
Rollbacks / day196Commit-before-pay ordering — mutations persisted before payment confirmedArea 2
Bad debt from upgrades / day48 (peak)Uncollectible invoices from failed rollbacks that left orphaned chargesArea 2 → 3
Disagreeing accounts691Handlers writing subsets of shared state, no component reads all five storesArea 3
Invoice coverage19%Each handler covers one Stripe event type — 64 of 342 paths coveredArea 3
CUSTESC escalation increase+44%Customers hitting silent failures with no dashboard visibilityAll areas
Upgrade 3DS Challenge Outcome Lost Uncollectible Bad Debt Stuck

The cascade starts in Area 2: a subscription upgrade commits state before payment confirms. If 3DS authentication is required and the customer abandons, the payment outcome is lost. The system has already provisioned entitlements and published events. Rollback is attempted but incomplete — the invoice becomes uncollectible, the account enters bad debt, and the customer is stuck with no self-service path to resolution. 196 times per day.