############################################################################### # Stripe — Checkout + Subscriptions (B-2.7 / B-2.8) — v7.0 pricing ############################################################################### # # Required for the /checkout/ flow and the /webhooks/stripe receiver. # The application will boot without these — billing routes will redirect to # /tarifs with a "contact info@dictia.ca" message until the keys are set. # # Get these from https://dashboard.stripe.com (CAD account) # - Use sk_test_/pk_test_/whsec_test_ keys against the Stripe test mode for # pre-prod. Switch to live keys ONLY after end-to-end CAD/TVQ rehearsal. # STRIPE_SECRET_KEY=sk_test_... # or sk_live_... # STRIPE_PUBLISHABLE_KEY=pk_test_... # used client-side; not strictly needed for hosted Checkout # STRIPE_WEBHOOK_SECRET=whsec_... # for B-2.8 webhook signature verification ############################################################################### # Price IDs — v7.0 (Cloud Basic / Essentiel / Pro + DictIA Local) ############################################################################### # # Format: price_xxxxxxxxxxxxxxxxxxxxxxxxxx # Naming convention in this codebase: STRIPE__ # PLAN = CLOUD_BASIC | CLOUD_ESSENTIEL | CLOUD_PRO | DICTIA_LOCAL # TYPE = SETUP (one-time) | MONTHLY | YEARLY | RENEWAL_YEARLY (DictIA Local An 2+) # # Yearly Price = Monthly Price × 12 × 0.85 (15 % discount). Configure both # Prices in the Stripe Dashboard for each Cloud plan. # Pro+ is quote-only — NO Stripe Price IDs (the route redirects to /contact). # Cloud BASIC : 189 $/mo (no setup) — solopreneur, petite équipe, ~165 h audio/mo # STRIPE_CLOUD_BASIC_MONTHLY=price_xxx # STRIPE_CLOUD_BASIC_YEARLY=price_xxx # Cloud ESSENTIEL : 349 $/mo (no setup) — cabinet en croissance, ~330 h audio/mo # STRIPE_CLOUD_ESSENTIEL_MONTHLY=price_xxx # STRIPE_CLOUD_ESSENTIEL_YEARLY=price_xxx # Cloud PRO : 549 $/mo + 485 $ onboarding (one-time) — usage intensif, ~660 h audio/mo # STRIPE_CLOUD_PRO_SETUP=price_xxx # STRIPE_CLOUD_PRO_MONTHLY=price_xxx # STRIPE_CLOUD_PRO_YEARLY=price_xxx # DictIA LOCAL : 5 998 $ An 1 (one-time matériel + 1ère année logiciel) puis 500 $/an dès An 2 # STRIPE_DICTIA_LOCAL_SETUP=price_xxx # STRIPE_DICTIA_LOCAL_RENEWAL_YEARLY=price_xxx ############################################################################### # Required Stripe Dashboard configuration ############################################################################### # # 1. Activate CAD currency on the account (Settings → Account → Currencies). # # 2. Enable Stripe Tax with TPS (5 %) and TVQ (9.975 %) for Quebec # (Tax → Settings → Tax registrations → Canada → Quebec). # All Checkout Sessions are created with `automatic_tax: { enabled: true }` # and `billing_address_collection: required` so Stripe computes taxes. # # 3. Enable Apple Pay + Google Pay # (Settings → Payment methods → Apple Pay, Google Pay). # Apple Pay requires verifying the dictia.ca domain via the Stripe-hosted # `.well-known/apple-developer-merchantid-domain-association` file. # # 4. For each Cloud plan, create: # - One recurring monthly Price (CAD, billing_scheme=per_unit) # - One recurring yearly Price (CAD, = monthly × 12 × 0.85) # For Cloud PRO, also create a one-time Price for the 485 $ setup fee. # For DictIA LOCAL, create: # - One one-time Price for 5 998 $ (An 1 — matériel + logiciel) # - One recurring yearly Price for 500 $ (renewal — MAJ + support dès An 2) # # 5. Create a webhook endpoint (B-2.8) pointing at # https://your-domain.example/checkout/webhooks/stripe # (the route lives under the /checkout/* prefix; CSRF-exempt; signature- # verified via STRIPE_WEBHOOK_SECRET below). # # Subscribe at minimum to these 5 events (the only ones the handler # processes; all others are acknowledged with 200 + ignored): # - checkout.session.completed (creates Subscription row, sets # User.subscription_status='active') # - customer.subscription.updated (status / current_period_end sync) # - customer.subscription.deleted (marks status='canceled') # - invoice.payment_succeeded (renewal touch; recovers past_due) # - invoice.payment_failed (marks status='past_due') # # Copy the signing secret (whsec_...) into STRIPE_WEBHOOK_SECRET above. # Without that secret, the webhook endpoint returns 400 invalid_signature # on every delivery (Stripe will retry for up to 30 days).