Escrow

Money & ledger

Integer cents, double-entry, Stripe pre-auth when you add a key. Demo still posts a balanced journal.

Loop · Booking hold, capture at completion, payout on demand

Escrow & ledger

Double-entry cents. Demo writes the journal without Stripe. Production refuses if GO_LIVE blockers remain.

POST /api/v1/payments/holds
  1. Authorize hold (stripe_pending ↔ platform_clearing).
  2. Capture splits fees, insurance pool, host payable, optional driver share.
  3. Refund reverses clearing to the processor.
  4. Cash-out moves payable to stripe_pending (Connect transfer in production).

backend/modules/payments/domain/ledger.ts

holdAtBooking / captureAndSplitZero-sum journals

backend/modules/payments/application/escrow.ts

EscrowServiceStripe when keys exist

backend/shared/golive/status.ts

assertProductionMoneyGo-live gate

$0 demo: Simulated PaymentIntent. Ledger still balances to zero.Scale: STRIPE_SECRET_KEY + Stripe Connect. No Adyen required.

Holds debit stripe_pending and credit platform_clearing. Capture spends clearing into platform_fees, insurance_pool, and host_payable. Tests fail if a journal does not sum to zero.

Program books (the three portals) are a separate identity from the trip ledger: $25 driver-paid = $15 host + $8 Period 2 binder + $2 platform. Owner, driver, and /admin/income read lib/reporting/books.ts. Print statements and 1099 worksheets use those totals. Stripe is still the wallet. See /docs/reporting.

AccountMeaning
stripe_pendingProcessor / Connect in flight
platform_clearingEscrow while the trip is live
platform_feesTake rate
insurance_poolPeriod 2 reserve
host_payable / driver_payableWhat we owe after capture
dispute_reserveChargeback shelf