product

DreamPro Coaching — Stripe checkout + split webhook

The money-in path that turns the (already-built) split engine into real revenue. Code is shipped but inert until you create a Stripe price + enable the webhook event + (for payouts) onboard Connect accounts. This doc is the wiring + test runbook. Companion to DREAMPRO_COACHING_CHANNEL_SCHEMA.md.

What's shipped (inert)

  • POST /api/coaching/checkout (payment.ts) — creates a Stripe Checkout subscription session for the caller's coaching membership. Stamps plan_key=coaching_subscription + membership_id on the subscription metadata (subscription_data.metadata) so every recurring invoice can resolve the membership. Returns 503 until STRIPE_PRICE_COACHING is set.
  • priceToPlanKey maps STRIPE_PRICE_COACHINGcoaching_subscription.
  • Webhook invoice.payment_succeeded case — isolated (own try/catch), no-ops for any non-coaching subscription. For a coaching sub it calls recordCoachingInvoiceSplit({ membershipId, grossCents: invoice.amount_paid, invoiceId }) → two creator_earnings rows (coach + override), pending. The money guard skips is_seed / AI-persona memberships.

Now shipped (since this doc was first written)

  1. Subscribe surface/coaching/subscribe POSTs /api/coaching/checkout and redirects to session.url; 503s with a friendly message until STRIPE_PRICE_COACHING is set.
  2. Connect transfers (payout-out)payoutPendingCoachingEarnings() (coaching-payouts.ts) transfers pending earnings to each payee's Connect account, stamping stripe_transfer_id + flipping pending → transferred. It runs on the daily coaching_payouts cron (index.ts), doubly gated: the cron toggle (/dashboard/admin/crons) AND env COACHING_PAYOUTS_ENABLED (the fn is a no-op when unset).
  3. Coach payout onboarding — the "Get paid" card on /dashboard/coaching runs Connect onboarding (/api/creator/payouts/onboard-link) + shows the coach's own earnings (/api/coaching/my-earnings). Coaches without an onboarded account are skipped by the cron (their earnings stay pending).
  4. Partner dashboard/dashboard/coaching/partner shows the network-wide override balance (pending vs paid) + coach roster.

Go-live order + env/cron checklist: DREAMPRO_COACHING_GO_LIVE.md (Parts D + E).

Wiring (one-time)

  1. Stripe Dashboard → create a recurring Price for DreamPro Coaching (e.g. $29/mo). Copy the price id.
  2. Env (backend / Railway): STRIPE_PRICE_COACHING=price_…
  3. Stripe Dashboard → Webhooks: on the existing endpoint (/api/payment/webhook), enable the invoice.payment_succeeded event (and checkout.session.completed
    • customer.subscription.* if not already). The signing secret is unchanged.
  4. (Payouts, later) coaches + the channel partner each finish Stripe Connect onboarding via the existing /api/creator/payouts/onboard-link.

Test plan (Stripe test mode)

  1. Set STRIPE_PRICE_COACHING to a test-mode price; use test webhook secret.
  2. Enroll a real (non-seed) client via a /start/<slug>?ref=<coach-code> link (creates the coaching_memberships row the checkout needs).
  3. Hit POST /api/coaching/checkout (or the future button) → complete Stripe Checkout with test card 4242 4242 4242 4242.
  4. Confirm invoice.payment_succeeded fires → check creator_earnings has a coaching_subscription row (coach share + platform share) and a coaching_override row (partner share), both pending, same stripe_invoice_id.
  5. Verify the money guard: repeat against a seed/persona membership → no earnings rows (the webhook logs recorded: false, reason: 'seed membership…').
  6. Verify idempotency: replay the webhook → no duplicate rows (dedup on stripe_invoice_id + coaching_subscription).
  7. The split totals appear in the super-admin earnings panel on /dashboard/coaching.

Safety notes

  • The webhook case is additive + isolated — it only acts on subscriptions whose metadata says coaching_subscription; everything else (Graphene+, etc.) is untouched. A coaching-split error is caught locally and never fails the webhook for other events.
  • Nothing moves real money yet: earnings are recorded pending; transfers are the explicit follow-on above.
DREAMPRO COACHING STRIPE — Docs | HiveJournal