/portal/api/billing/{summary,usage,estimate,invoices,invoices/:id/pay[/confirm],
payment-methods[/setup-intent|/checkout-session|/:id|/:id/default],po} behind the
portal session; staff routes for storage samples and purchase orders.
Additive tables storage_samples and purchase_orders (CREATE TABLE IF NOT EXISTS).
Card routes 503 without a real Stripe key; nothing charges without customer
confirmation. 9 new tests; full suite 283/283.
Docs and comments only, no behavior change:
- src/pricing.ts: fix two comments that said +20% / AWS x1.20 (the code is 2500 bps = x1.25)
- tests/peergos-billing.test.ts: fix test title and arithmetic comment (2875 millicents -> 29c, which the test already asserts)
- docs/PEERGOS-BILLING.md: hosted overage AWS x1.25; clarify that the 1.5/0.75 multipliers are timestamp-only; flag the cust-platform default as contradicting D3; add a decisions D1-D6 section
- docs/ACCOUNTING.md, docs/CUSTOMER-PORTAL.md: mark prepaid drawdown as current behavior and note the planned Stripe subscription collection (D1)
Defer meter recording for single stamps so upstream failures (402/5xx)
do not bill customers. commitMeteredUsage on 2xx/mock; abandonMeteredUsage
zeros X-Verae-Credits-Spend on failure. Batch path unchanged.
- Document that 402 QUOTA_EXCEEDED (51/50) is the verae-zapier-middleware shared
tenant free-plan quota, not a customer balance gate; edge passes it through
fail-closed (no mock certs).
- tests/negative-balance.test.ts locks in: negative balance_cents still stamps.
- src/jobs/overdue-balances.ts: effective balance = prepaid - unpaid issued
invoices - unbilled usage; dry-run by default, --send uses existing mailer
(SMTP_FROM). systemd unit/timer stubs in deploy/systemd.
- src/billing/signup-credit.ts: SIGNUP_CREDIT_CENTS (default 5000) granted on
new portal signup and admin create via credit ledger + ledgerAdjust;
idempotent, no double grant on claim; admin create 409 on existing id.
- docs/NEGATIVE-BALANCE.md
Sync live /opt/verae/zappier-edge tree, then stop inventing mock-cert-*
receipts in production.
- When ZAPPIER_UPSTREAM is set and upstream is missing/non-2xx, return
upstream status (or 502) with error=upstream_timestamp_failed
- Dev-only mock-cert-* behind ALLOW_MOCK_CERTS=true when upstream unset
- Tests for fail-closed single/batch paths; mock tests set ALLOW_MOCK_CERTS