Whop × Refr

Payout Integration Guide

Replace Stripe Connect payouts with Whop — 180+ countries, instant cashout, built-in KYC and 1099 compliance. Stripe stays for pay-ins. Side-by-side, no rip-and-replace.

Stripe Connect Payouts → Whop Transfers Stripe KYC → Whop KYC Stripe Pay-ins stay Subscriptions stay No new dependencies

Start Here — Drop This Into Your Repo

This file gives Cursor and Claude Code full context on the payout migration. Every file path, schema change, and TypeScript code example — scoped to payouts only.

Save as CLAUDE.md in your project root. Open Cursor. Say “implement the Whop payout migration.”

Replace Stripe Connect payouts with Whop in the refr-app codebase. PAYOUTS ONLY — Stripe stays for pay-ins, subscriptions, invoices. Key files: src/pages/api/stripe/connect/* (add Whop path alongside Stripe), src/pages/api/stripe/payouts/* (add Whop transfers), src/pages/api/stripe/webhook/connect.ts (add Whop webhook). Create src/lib/whop.ts (API client), src/lib/payout-provider.ts (routing), src/pages/api/whop/webhook.ts (webhook handler). Add payout_provider + whop_company_id columns to accounts table. Remove scheduled make-transfers edge function — payouts are now user-initiated via embedded Whop PayoutsSession. Use PAYOUT_PROVIDER env var for global routing, accounts.payout_provider for per-user override. Stripe stays default until full rollout.

Rollout Strategy

Whop runs alongside Stripe Connect in production. Stripe handles ALL pay-ins, Whop handles payouts for opted-in users.

PAYOUT_PROVIDER env var defaults to "stripe". Per-user override: accounts.payout_provider column. All routing lives in src/lib/payout-provider.ts — one function, not scattered across files.
1

Build

Whop client, webhook handler, migration, both payout paths. Stripe stays default. Deploy with zero behavior change.

2

Internal Test

Set accounts.payout_provider to "whop" on your own test accounts. Transfer real money.

3

New Signups

July 1st: new assignors/referees default to Whop. Existing accounts stay on Stripe Connect.

4

Full Migration

Transition existing accounts over 3–6 months. Stripe Connect path stays as fallback.

Money Flow

How funds move from organizations to assignors and referees via Whop.

Referee / Assignor Payout

Organization Stripe Pay-in
Platform Whop Balance
Transfer Ref Wallet
User-initiated Withdrawal

Replaces stripe.transfers.create in src/pages/api/stripe/connect/transfers.ts. Scheduled batch edge functions removed — withdrawals are now user-initiated.

Submerchant Onboarding & KYC

Referee Signs up
Whop Account Created
First Withdrawal KYC Triggered
Verified 1099 Compliant

Replaces stripe.accounts.create + stripe.accountLinks.create in src/pages/api/stripe/connect/account.ts. KYC only at first withdrawal — $5K hold limit pre-KYC.

Your Code → Whop

How your existing schemas and modules map to Whop. Only payout-related tables change.

Your SchemaFileWhop EntityNew Columns
accountssupabase/migrations/schema_init.sqlCompany (connected account)whop_company_id TEXT, payout_provider TEXT
transactionssupabase/migrations/schema_init.sqlTransfer (ctt_xxx)provider TEXT, status TEXT
profilessupabase/migrations/schema_init.sqlNo changes
customerssupabase/migrations/schema_init.sqlNo changes (Stripe pay-in)
gamessupabase/migrations/schema_init.sqlNo changes (fee logic stays)
New tablemigrationWebhook idempotencywhop_webhook_events

What Changes

Side-by-side: the Stripe Connect calls you have today vs. the Whop equivalents. Only payout routes change.

Stripe Connect (Today)

  • accounts.create — onboard referee
  • accountLinks.create — KYC link
  • transfers.create — send payout
  • accounts.retrieve — check status
  • Scheduled batch edge functions
  • 5-day ACH settlement

Whop (After)

  • POST /companies — create account
  • POST /account-links — KYC link
  • POST /transfers — send payout
  • GET /companies/{id} — check status
  • User-initiated withdrawals
  • 1–3 day settlement (70% within 24h)

Webhook Mapping

Stripe pay-in webhooks stay unchanged. Only Connect payout events get a Whop equivalent.

Stripe Connect EventWhop EventWhat Happens
account.updatedcompany.createdSet accounts.completed = true after verification
None (batch function)transfer.completedTransfer to referee confirmed
Nonewithdrawal.completedReferee withdrew to bank/crypto
Nonewithdrawal.failedWithdrawal failed — alert user
Nonepayment.succeededPlatform top-up confirmed
Three webhook endpoints coexist: /api/stripe/webhook (pay-ins — unchanged), /api/stripe/webhook/connect (Stripe Connect accounts), and /api/whop/webhook (Whop payout events).

Architecture

Where Whop fits. Orange is new, green stays unchanged. Both payout providers coexist.

          ┌────────────────────┐
          │ Organizations      │    PAY-INS (Stripe — unchanged)
          │ (invoices, charges) │
          └─────────┬──────────┘┌─────────┴──────────┐
          │ Stripe Checkout     │
          │ Invoices, Subs      │
          └─────────┬──────────┘┌─────────┴──────────┐
          │ Refr Platform       │    PAYOUTS (provider routing)
           getPayoutProvider()  
          └────┬─────────────┬────┘
               │             │
   provider=   │             │   provider=
   "stripe"    │             │   "whop"
               │             │
    ┌───────┴───┐   ┌────┴───────┐
    │ Stripe     │   │ Whop API    │
    │ Connect    │   │ /transfers  │
    └─────┬─────┘   └────┬───────┘
          │                  │
          │             ┌───┴───────┐│ Ref Wallet  ││ (user-init) │└────┬───────┘
          │                  │
    ┌─────┴────────────┴────┐
    │  Assignor / Referee      │
    │  Bank / Crypto / Venmo    │
    └────────────────────────┘

Timeline — 1 Week

Payouts-only scope keeps this tight. Stripe stays live for pay-ins the entire time.

Day 1–2
Build
  • Whop client + provider routing
  • DB migration (2 cols + 1 table)
  • Webhook handler
  • Deploy — Stripe still default
Day 3–4
Wire & Test
  • Connect account creation + KYC flow
  • Transfer + withdrawal end-to-end
  • Embedded PayoutsSession in finance page
  • Test with real money on internal accounts
Day 5–6
Validate
  • Flip 5–10 trusted assignors to Whop
  • Confirm transfer parity + webhooks
  • Verify Stripe pay-ins still work
Day 7
Go Live
  • New signups default to Whop
  • Existing accounts migrate in waves
  • Stripe Connect stays as fallback

What Stays the Same

Most of your stack is unchanged. Whop replaces only the payout and onboarding layer.

Stripe Checkout
Stripe Invoices
Stripe Subscriptions
Stripe Billing Portal
Next.js 13.5 + React 18
Supabase PostgreSQL
NextAuth + JWT
Netlify hosting
Game scheduling
Fee calculation logic
Yardstik background checks
No new dependencies
~ accounts table (2 new cols)
~ finance page (payout embed)
Bottom line: All pay-in flows (checkout, invoices, subscriptions, billing portal) are completely untouched. Stripe Elements stays. Fee calculation stays. The Whop client uses built-in fetch — no new dependencies.