Payments, Checkout, Coupons & Upsells
Payments, Checkout, Coupons & Upsells
Section titled “Payments, Checkout, Coupons & Upsells”Who this is for: support staff (billing questions), PMs, finance-adjacent staff, new hires.
Checkout
Section titled “Checkout”- When a patient reaches the payment step of their case, the price shown is always recalculated on the server from the case’s configured price for that service/state — the system never trusts a price sent from the patient’s browser.
- The patient pays by credit/debit card through the platform’s payment processor.
- Successful payment marks the case as paid and fires a “case paid” event, which is what allows the case to move forward (booking, intake, etc.) and is also the trigger for referral rewards (see Referrals).
Three checkout page designs, one shared backend
Section titled “Three checkout page designs, one shared backend”The patient portal actually has three different-looking checkout page implementations (a standard one, an alternate-design one, and an FMLA-specific one), plus matching pairs for the pre-payment summary and payment-processing screens. Which one a patient sees depends on which onboarding funnel they came from and, for FMLA, the service configuration’s checkout setting — but all three call the exact same underlying pricing/payment logic, so behavior (and any pricing bug fix) is consistent across all three regardless of which one is shown.
A note on the care portal’s own payment webhook
Section titled “A note on the care portal’s own payment webhook”The care portal has its own copy of a Stripe payment webhook, but it is currently disabled (commented out) in the codebase — the live, active Stripe webhook that actually processes payment confirmations today lives in the patient portal. This is worth knowing if you’re troubleshooting a payment that didn’t register: check the patient portal’s webhook logs, not the care portal’s.
Coupons and discounts
Section titled “Coupons and discounts”- Coupons can be a fixed dollar amount off or a percentage off, and are scoped to a specific brand.
- Coupons can optionally expire or be turned inactive.
- A discount can never make the price go below zero.
- If a coupon (or a free promotional service) brings the price all the way to zero, checkout skips the payment processor entirely and the case is marked paid directly — but it still fires the same “case paid” event as a real charge, so downstream steps behave the same either way.
Upsells and add-ons
Section titled “Upsells and add-ons”- Some services can offer the patient an additional related service at specific moments in their journey — before starting intake, after finishing intake, or on a dedicated add-on checkout screen.
- Whether upsell offers are shown at all, and at which of those moments, is a configurable setting per brand.
- If a patient buys an add-on service, it is created as its own case, automatically linked to the same doctor as the original case.
Where the money goes (internal note)
Section titled “Where the money goes (internal note)”For each paid case, the system tracks an internal breakdown of the payment: a support-operations share, an estimated payment-processing fee, the doctor’s payout, and the remaining company revenue share. This breakdown is for internal financial tracking — it is not shown to the patient.
Open questions
Section titled “Open questions”- Whether there are usage caps (e.g. “one use per patient”) enforced on coupon codes was not confirmed in the code reviewed — flagged as a real risk area worth double-checking with the team, since a reusable 100%-off coupon combined with the “skip payment processor” free-checkout path could be used repeatedly.
Where this comes from
Section titled “Where this comes from”parkingmd-patient-portal/src/trpc/routers/checkout/(index.ts,helpers.ts)parkingmd-patient-portal/src/models/coupons.tsparkingmd-patient-portal/src/lib/upsell.tsparkingmd-patient-portal/documentation/service-flow.md(section 5 — addon services and upsells)parkingmd-care-portal/docs/upsell-care-portal-blueprint.mdparkingmd-care-portal/src/lib/stripe.ts(refund handling)parkingmd-patient-portal/documentation/additional-documents-plan.md(historical planning note only — used solely for the risk flag above, not as fact about current behavior)parkingmd-patient-portal/src/app/task/[taskid]/checkout/,checkout-flow/,checkout-new/(three page implementations sharingtrpc/routers/checkout/)parkingmd-patient-portal/src/components/*/CheckoutCard.tsx(pickscheckoutvscheckout-newbased onserviceConfigurations.checkoutUrl)parkingmd-care-portal/src/app/api/webhooks/stripe/route.ts(disabled/commented out) vs.parkingmd-patient-portal/src/app/api/webhooks/stripe/route.ts(the live one)