| 1 | # π€ Managed payments β the payout model for paid access levels |
| 2 | |
| 3 | Design doc, 2026-07-22. Status: **designed, not built** (umbrella issue links |
| 4 | the phases). Companion docs: `docs/community-and-tiers.md` (layer 3 β the tier |
| 5 | machinery money assigns into), `docs/tier-economics.md` (the hosting price |
| 6 | book; a different product, same Stripe account), `docs/pricing-bands.md`. |
| 7 | Decisions here are Paul's (2026-07-22); the VAT/OSS findings are research |
| 8 | summaries, not legal advice β a human review gates the go-live phase. |
| 9 | |
| 10 | ## The design in one sentence |
| 11 | |
| 12 | > **Members pay the platform and the admin's share transfers structurally β |
| 13 | > no Stripe account required, commission pay-what-you-want between 5.5% and |
| 14 | > 11% all-in β while "bring your own Stripe" stays open to every space, with |
| 15 | > a pay-what-you-want commission (suggested 5.5%) on top of the admin's own |
| 16 | > fees.** |
| 17 | |
| 18 | ## Two providers, priced by who bears the risk |
| 19 | |
| 20 | | | Managed (default) | BYO Stripe (open to every space) | |
| 21 | |---|---|---| |
| 22 | | Merchant of record | the platform | the space admin | |
| 23 | | Stripe account | ours; admin gets an **Express** account (payouts + KYC only) | admin's own (OAuth-linked Standard, today's live path) | |
| 24 | | Commission | **pay-what-you-want, 5.5β11%, suggested 11 β all-in** (card processing fees come out of our points, whatever the choice) | **pay-what-you-want, suggested 5.5%** + the admin's own Stripe fees | |
| 25 | | VAT on member subscriptions | ours (OSS from Ireland; Stripe Tax) | admin's | |
| 26 | | Disputes/refunds | ours (payout holds; transfer reversals) | admin's | |
| 27 | | Admin onboarding | minutes (Express account links: name, bank, KYC) | needs a real Stripe account | |
| 28 | |
| 29 | Both commissions are the honor mechanism from `pricing-bands.md` applied to |
| 30 | our own cut: a suggestion, a one-tap choice, no eligibility test. The two |
| 31 | rails bound it differently because the costs differ: |
| 32 | |
| 33 | - **Managed clamps to [5.5, 11]** because we bear real per-charge costs |
| 34 | (processing, VAT handling, disputes). The 5.5 floor is roughly our cost |
| 35 | line β on the β¬5.50 minimum ticket with an international card it dips a |
| 36 | couple of points under, and that known loss is priced in rather than |
| 37 | guarded against. |
| 38 | - **BYO is unbounded down to zero** because our marginal cost there is nil β |
| 39 | the admin is the merchant, pays their own fees, runs their own books. Any |
| 40 | commission they choose is honest margin; zero is a legitimate choice. |
| 41 | |
| 42 | Why this split, in order of weight: |
| 43 | |
| 44 | 1. **Activation.** BYO filters monetization to admins who already run a |
| 45 | business. A Family or Community admin has no Stripe account and never |
| 46 | will; Express onboarding is a bank account and a KYC form. Managed is the |
| 47 | 95% case. |
| 48 | 2. **"All-in, including payment fees" becomes structural.** On a |
| 49 | destination charge we own the charge and pay Stripe's processing fee from |
| 50 | our own take; the admin's share is set by `transfer_data` from their |
| 51 | chosen commission, not reconciled after the fact. The |
| 52 | refund-reconciliation and fee-prediction designs this supersedes are |
| 53 | recorded below (Β§ Superseded) so they aren't reinvented. |
| 54 | 3. **The cuts price the risk transfer β and both are the admin's call.** |
| 55 | Managed bears processing + VAT + disputes, so its pay-what-you-want range |
| 56 | floors at 5.5 (β our cost line); BYO bears all three itself, keeps its |
| 57 | own books and negotiated rates, so its commission is open all the way to |
| 58 | zero, suggested 5.5 (market-honest: Memberful charges 4.9% flat for the |
| 59 | same shape; Substack takes 10 *plus* processing). |
| 60 | |
| 61 | ## Money mechanics (managed) |
| 62 | |
| 63 | - Checkout Sessions on the **platform account** (no `Stripe-Account` header), |
| 64 | `mode=subscription`, `subscription_data[transfer_data][destination]` = the |
| 65 | space's Express account, `[amount_percent]` = 100 β the chosen commission |
| 66 | (89β94.5). Stripe splits every invoice; processing fees land on the |
| 67 | platform side by construction. |
| 68 | - **Level price floors: β¬5.50/month, β¬11/year** (enforced at level pricing |
| 69 | time, both providers). Stripe's fixed β¬0.25/charge makes all-in economics |
| 70 | negative below ~β¬2.60/charge and thin below β¬5; the floors keep the |
| 71 | worst-case (international card) take β₯ ~3 points. Same fee logic that made |
| 72 | Business and Family annual-only (`tier-economics.md`). |
| 73 | - Payouts ride Stripe Express schedules; a rolling payout delay (Stripe's |
| 74 | default) is the fraud/dispute buffer. Disputes: transfer reversal claws |
| 75 | back the transferred share; the β¬15 dispute fee is ours β priced into the |
| 76 | commission. |
| 77 | - VAT: the platform is seller of record for an electronically supplied |
| 78 | service. Consumer stickers are VAT-inclusive (the pricing-bands posture), |
| 79 | so our net per subscription varies by buyer country; OSS (one Irish |
| 80 | registration) covers the EU, Stripe Tax computes per-invoice. Non-EU |
| 81 | registrations (UK first) ratchet on thresholds. **A human tax review gates |
| 82 | the live flip** β same bar as pricing-bands Phase 1. |
| 83 | |
| 84 | ## Trust model (the two honest costs) |
| 85 | |
| 86 | - **Privacy centralization.** Today each admin's Stripe sees only their own |
| 87 | members' payment identity; managed payments concentrates every paying |
| 88 | member of every space into one Stripe dashboard. Our own stores still hold |
| 89 | only opaque ids (the billing.go rule), but the dashboard exposure is real |
| 90 | and grows with the fleet. Named here deliberately; BYO remains the |
| 91 | decentralized escape hatch, and that is part of why it stays. |
| 92 | - **Merchant of record for content we cannot see.** E2EE means we underwrite |
| 93 | payments for communities whose content is structurally opaque to us. |
| 94 | Mitigations: the existing report-to-admins/moderation surface, payout |
| 95 | holds, and the standing right to off-board a space from *payments* |
| 96 | (payouts stop; the space itself, being E2EE, was never ours to read). |
| 97 | This asymmetry β we can stop paying out, we cannot inspect β is the |
| 98 | design, not a gap in it. |
| 99 | |
| 100 | ## Implementation shape |
| 101 | |
| 102 | - `subscriptions.go` already has the seam: `PayProvider` is an interface and |
| 103 | "adding a provider never touches the state machine." `stripePlatform` |
| 104 | (managed) lands beside `stripeConnect` (BYO). Normalized `SubEvent`s feed |
| 105 | the same `applySubEvent`. |
| 106 | - Provider selection per space: managed is the default wherever platform |
| 107 | creds exist; `stripe_connect_account` (BYO) stays available to every |
| 108 | space β no tier gate. A space that links its own Stripe chooses the BYO |
| 109 | rail by that act. |
| 110 | - Commission choices live in the space config: `managed_commission_pct` |
| 111 | (clamped [5.5, 11], default 11) and, phase 3, the BYO percent (suggested |
| 112 | 5.5, floor 0). Changing a choice applies to new checkouts; existing |
| 113 | subscriptions keep the split they were created with. |
| 114 | - Express account id lives in the space config (`stripe_express_account`), |
| 115 | set by the onboarding flow (Account Links API; `account.updated` webhooks |
| 116 | flip the payouts-ready bit). Until payouts-ready, levels can be drafted |
| 117 | but not sold β never sell against an account that can't be paid. |
| 118 | - Level prices: managed levels create their Stripe Price on the platform |
| 119 | account (BYO keeps creating them on the admin's). The floors apply in the |
| 120 | level-pricing path, before any Stripe call. |
| 121 | - Existing BYO spaces (paulca) are grandfathered: linked accounts keep |
| 122 | working; the 10% β pay-what-you-want change (suggested 5.5) applies from |
| 123 | its deploy β a cut *reduction* at the suggestion, so no notice period. |
| 124 | |
| 125 | ## Lifetime access (single payment) |
| 126 | |
| 127 | A level can price as **`interval: "once"`** β pay once, in for as long as the |
| 128 | space exists (PR #1290; both rails). The copy says "as long as the space |
| 129 | exists" deliberately: an admin can close a space, and we don't sell promises |
| 130 | admins can't keep. Mechanics: `mode=payment` checkouts with the commission as |
| 131 | a fixed amount (payment mode has no percent splits) β BYO takes its flat fee, |
| 132 | managed applies the chosen PWYW commission to the transfer. The grant has no |
| 133 | lifecycle β exempt from every renewal-shaped sweep β and the only exits are a |
| 134 | refund/chargeback (`charge.refunded` / `charge.dispute.created` revoke |
| 135 | immediately, with a payment-intent tombstone so redelivered grants can't |
| 136 | re-buy a refunded level) or an admin removal. **Floor: 11.00 one-time** β |
| 137 | the elevens' third coin (β¬5.50/month, β¬11/year, β¬11 once). |
| 138 | |
| 139 | ## Rollout phases (mirrored in the umbrella issue) |
| 140 | |
| 141 | 1. **Provider core (dark):** `stripePlatform` + destination-charge checkout |
| 142 | + webhook parse + tests; config-gated off. |
| 143 | 2. **Express onboarding:** account links flow, payouts-ready gating, admin |
| 144 | UI (web + native surfaces per parity rule). |
| 145 | 3. **Floors + BYO repricing:** β¬5.50/β¬11 level-price floors both |
| 146 | providers; BYO's application fee becomes the pay-what-you-want config |
| 147 | (suggested 5.5, floor 0) with its admin picker; changelog. |
| 148 | 4. **Tax + go-live:** Stripe Tax on, OSS registration confirmed, human tax |
| 149 | review, live platform creds, docs/status updates. |
| 150 | |
| 151 | ## Superseded designs (recorded so they stay dead) |
| 152 | |
| 153 | - **Fee-refund reconciliation** (charge 11%, refund the actual |
| 154 | `balance_transaction.fee` after `invoice.paid`): correct but only needed |
| 155 | when the admin is MoR and we promise all-in β i.e. never, under this |
| 156 | split. BYO makes no all-in promise; managed doesn't need reconciliation. |
| 157 | - **Fee prediction from the payment intent**: impossible before the first |
| 158 | charge (no card yet), asymmetric on renewals (application fees refund |
| 159 | down, never up). Reconciliation was prediction with the error bar |
| 160 | collapsed; destination charges remove the need for either. |
| 161 | |