ADR: Stripe Owns Full Billing Stack Except Invoice Presentation¶
- Status: Accepted
- Date: 2026-04-23
- Decider: Jeffrey Lambert
- Project: Stripe Billing Transition
Context¶
The viability assessment asked, subsystem-by-subsystem, what moves to Stripe. Jeffrey is already on Stripe Billing + Invoicing + Checkout, and wants to centralize as much billing logic as possible in Stripe — subscriptions, tiered pricing, metering, discounts, calculations, retries, dunning — while keeping only the invoice PDF look-and-feel in-house (see ADR 2026-04-23-custom-invoice-pdf-retained.md).
Decision¶
Stripe owns these subsystems as the system of record:
| Subsystem | Stripe product | Notes |
|---|---|---|
| Customer record | Customer |
Adventive carries a thin customer mirror for joins against product data |
| Product / price catalog | Product, Price |
Full migration of pricing to Stripe |
| Subscriptions | Stripe Billing subscriptions | Covers flat, tiered, and hybrid pricing |
| Usage-based / metered | Stripe Billing metered prices + usage records | Adventive reports meters, Stripe calculates |
| Discounts / coupons | Coupon, PromotionCode |
|
| Invoice assembly | Invoice, InvoiceItem |
Items attached as they accrue, not rolled up at month-end |
| Tax calculation | Stripe Tax (future) | Not enabled today — wired up when tax liability triggers |
| Failed-payment retries | Stripe Billing Smart Retries | Replaces any custom retry logic |
| Dunning emails | Stripe Billing dunning (decided 2026-04-23) | Stripe owns the full failed-payment lifecycle: retries, dunning sequence, and customer comms. No custom dunning via Mailgun. |
| Payment collection | Stripe + Hosted Invoice Page | Unchanged |
| Disputes | Stripe Radar + API | |
| Refunds / credits | Stripe Refunds + Credit Notes | |
| Accounting sync | Acodei → QuickBooks (unchanged) | Stripe events, captured by Acodei, pushed to QuickBooks |
Adventive owns:
| Subsystem | Rationale |
|---|---|
| Invoice PDF rendering | Brand fidelity non-negotiable (separate ADR) |
| Email delivery | Mailgun is a shared service — auth emails, onboarding, billing, etc. Kept |
| Metering signal source | Adventive products know what usage to meter; Stripe receives usage reports |
| Operator-side billing UI | Surfaced in the new admin (Stripe data, Adventive presentation) |
Retiring the monthly rollup¶
The current pipeline accumulates billable events internally, then rolls up at month-end and creates a Stripe invoice. After this transition:
- Billable events are posted to Stripe as
InvoiceItems on the customer's draft invoice as they happen (or via scheduled Worker flushes if batch-friendly). - Stripe's billing cycle controls finalization.
- The custom rollup job is retired.
This simplifies reconciliation — Stripe becomes the source of truth for what was billed, and Acodei syncs that directly to QuickBooks.
Customer portal¶
Stripe Customer Portal is in scope as an optional customer self-service surface (update card, see invoice history, download Adventive-branded PDFs). Final decision on enabling it is deferred — it's additive to the migration and doesn't gate cutover.
Consequences¶
Positive: - One source of truth for billing (Stripe) — reconciliation becomes trivial. - Stripe handles the things that are hard to get right (tax, retries, dunning, disputes, card updates). - Acodei → QuickBooks pipeline simplifies because it becomes purely Stripe-driven. - Retiring the rollup job + custom billing calculations removes significant admin-side complexity.
Negative / to-mitigate: - Stripe pricing model must exactly mirror Adventive's current pricing — mismatches would change customer charges. - Metering signal reliability becomes important — dropped usage events = lost revenue. - Stripe's billing cycle may not match Adventive's current month-end cadence for all customers → cutover plan needs per-customer cycle alignment. - Roughly 200 customers, mix of pricing models, some non-standard arrangements → migration must handle outliers individually.
Follow-ups¶
- Inventory current pricing models (flat / tiered / usage / discount / custom contracts) → map each to a Stripe construct.
- Plan the non-standard-arrangement handling strategy (Stripe can handle most, but some manual-invoice customers may need a separate flow).
- Define the metering event contract — what Adventive product emits, what the Worker posts to Stripe.
- Confirm Acodei's handling of the new Stripe event shape (invoice-item-per-event instead of month-end invoice-with-items).
- ~~Design the dunning decision~~ — Resolved 2026-04-23: Stripe handles dunning end-to-end. Follow-up is content review of Stripe's dunning email templates to confirm they meet Adventive's tone bar.