NUTRISYNCBuilders Hub
🏠 🛠
NUTRISYNC · Docs

29 · Payments & Subscriptions — In-Depth Proposal

Goal: a premium subscription that works day one in the Eurozone, UK, Australia, USA, Canada and (phased) LATAM — with renewals, cancellations and refunds handled by proven rails, not by us. Decision paper for founders; nothing is built yet.

1. The two market rules that shape everything

Rule 1 — In-app digital subscriptions must use the stores. Apple and Google require that digital goods sold inside the native apps go through In-App Purchase / Play Billing (15% fee up to $1M/yr via the small-business programs, 30% above). A Stripe checkout inside the iOS app for a subscription is a rejection. This is not a choice between "AWS shopping cart or others" — on mobile the rail is imposed.

Rule 2 — The web is free territory. On nutrisynccollective.com we can charge with any processor at ~2-3% instead of 15-30%. The classic play (Spotify model): sell on both, steer nothing illegally, and let the web be the margin-friendly door. The app can honor a web-purchased subscription without ever mentioning where to buy.

Corollary: we will run two sales rails with one source of truth for "is she premium?".

(Why not AWS: Amazon has no consumer cart/subscription product for this use case — Amazon Pay is a wallet button, not a billing engine. The AWS wave in our backlog is about compute, not checkout.)

2. Recommended architecture

   iOS app ──── StoreKit (Apple IAP) ──┐
   Android ──── Play Billing ──────────┤        webhooks     ┌──────────────────┐
                                       ├──► RevenueCat ────► │ Supabase          │
   Web ──────── Stripe Billing or ─────┘   (subscription     │ subscriptions tbl │
               Paddle (MoR)                 state hub)       │ + is_premium()    │
                                                             │ RLS gates         │
                                                             └──────────────────┘

3. Coverage by region (initial scope)

Region Mobile (IAP) Web
Eurozone, UK, USA, Canada, Australia Native — stores localize price & currency per storefront, handle taxes Stripe/Paddle native; cards + Apple Pay/Google Pay buttons
LATAM (phase) IAP works everywhere the stores operate; store handles local pricing tiers Cards work cross-border, but LATAM converts on local methods (PIX in Brazil, OXXO/SPEI in Mexico, local wallets). Launch LATAM web = cards only; add a local processor (dLocal / EBANX / Mercado Pago) only when the LATAM cohort is real

Pricing: use Apple/Google price tiers per storefront and Stripe/Paddle multi-currency price lists — one product, localized price points (LATAM sensitivity: plan regional tiers, not FX conversion).

4. Product shape & user flows

Offer: Free tier (current app) + NutriSync Premium — monthly and annual (annual with ~35-40% saving badge) + 7-day free trial. Exact prices = founders + tracker assumptions (doc G3).

A · Becoming a paying user (app): Onboarding stays free (never paywall registration — health apps die there). Paywall appears at value moments: the yearly Progress view (already a locked card today), advanced insights, and a soft card after the first completed cycle. Tap → Paywall screen → plan choice → native store sheet (Face ID confirms — note the elegance: the biometric decision from doc 28 composes with this) → receipt lands in RevenueCat → webhook flips subscriptions → premium unlocks live, all surfaces at once.

B · Becoming a paying user (web): marketing pricing section (exists today, currently waitlist-steered) → checkout hosted by Stripe/Paddle (card, Apple/Google Pay) → webhook → same table. She opens the app: already premium. One subscription per account enforced by the hub (RevenueCat blocks double-billing across stores).

C · Renewals: stores/processor auto-charge; webhook refreshes current_period_end. Failed card on web → dunning emails + grace period (7 days premium while retrying — standard, avoids rage-churn). App shows a quiet "billing issue" banner only in Settings.

D · Cancellation: never a support ticket. In-app "Manage subscription" deep-links to the store's own management sheet (Apple/Google requirement); web portal (Stripe Customer Portal / Paddle equivalent) for web subs. Cancelling = will_renew=false, premium runs to period end, then graceful downgrade (data never deleted — free tier keeps her history, premium features re-lock). Refunds & EU 14-day withdrawal: handled by the store/MoR per their policy; we honor state changes via webhook.

5. Design integration (hand-off to Design)

New surface inventory (added to doc 12 as §22):

  1. Paywall screen — hero with Nutri + benefit bullets phrased in cycle language, two plan cards (annual pre-selected with saving pill), trial CTA ("Prueba 7 días gratis"), "Restore purchases", tiny legal footer (auto-renewal wording the stores require). One screen, both stores.
  2. Locked-state pattern — we already have one (Progress yearly lockBox): consolidate it as the premium lock (blur + lock pill + one-line value + "Ver Premium").
  3. Settings → "Suscripción" row — state chip (Free / Premium · renews 12 Aug / Billing issue), manage/cancel link, restore.
  4. Success state — post-purchase confirmation reusing the SuccessRing pattern ("Premium activo").
  5. Web pricing page — connect the existing marketing pricing cards to real checkout (web rail) while app-store steering rules are respected per region.
  6. Grace/billing banner — Settings-only, non-nagging.

6. Decisions requested from founders

  1. Web rail: Paddle-type Merchant of Record (recommended at launch) vs Stripe direct (better margin, we own taxes)?
  2. Price points & trial length per region (feeds the G3 tracker assumptions).
  3. Which features are Premium at launch (proposal: yearly/advanced Progress, upcoming wearables, future community perks — the daily loop stays free).
  4. GO to add RevenueCat as the subscription hub.

7. Prerequisites & phasing

Hard prerequisite: the web rail (Stripe/Paddle) needs the company + bank account (doc 19) — it cannot start on a personal basis. Apple/Google IAP can start on the current individual account (banking + tax forms in App Store Connect) and transfers with the app later.

Phase Contents Depends on
P0 — foundation (can start now) subscriptions schema + is_premium() + RLS gating + paywall/locked/Settings UI behind a feature flag + RevenueCat account & SDK wiring nothing
P1 — mobile live IAP products in both stores, sandbox → TestFlight testing, prices per storefront P0 + banking/tax forms in ASC
P2 — web live Paddle-or-Stripe checkout + portal + webhooks company registered
P3 — LATAM depth local methods via dLocal/EBANX/MP, regional price tiers review real LATAM cohort

Effort: P0 ≈ 2 sessions · P1 ≈ 2 sessions + store review cycles · P2 ≈ 2 sessions. All gated behind a flag until founders flip it.