QUANHEX.
SaaS

Building Multi-Tenant SaaS with Stripe Connect

A practical walkthrough of designing marketplace billing for a multi-tenant SaaS platform using Stripe Connect, covering account onboarding, fee splitting, and subscription management.

· 8 min read

Multi-tenant billing is one of the areas where SaaS architecture gets genuinely hard. You’re not just charging customers — you’re operating a payment marketplace where money flows between your platform and sub-accounts. Stripe Connect is the right tool, but the mental model takes time to internalize.

The Three Account Types

Stripe Connect offers Standard, Express, and Custom connected accounts. For most SaaS platforms where vendors need some control but you want a consistent UX, Express accounts are the right choice.

  • Standard: Vendors manage their own Stripe dashboard. Maximum flexibility, minimum control.
  • Express: Vendors complete a Stripe-hosted onboarding flow. You control the experience, Stripe handles compliance.
  • Custom: You own the entire onboarding and dashboard UX. Maximum control, maximum liability.

Onboarding Flow

The onboarding pattern for Express accounts is:

  1. Your server creates an Account Link with account_links.create
  2. Redirect the vendor to the Stripe-hosted onboarding URL
  3. Stripe redirects back to your return_url with the account ID
  4. Store the stripe_account_id on your vendor/tenant record
  5. Check charges_enabled and payouts_enabled before allowing transactions
$accountLink = $stripe->accountLinks->create([
    'account' => $vendor->stripe_account_id,
    'refresh_url' => route('onboarding.refresh'),
    'return_url' => route('onboarding.complete'),
    'type' => 'account_onboarding',
]);

return redirect($accountLink->url);

Payment Intents with Application Fees

When a customer pays through your platform, you capture the payment and take a platform fee in a single operation:

$paymentIntent = $stripe->paymentIntents->create([
    'amount' => $totalAmount,
    'currency' => 'usd',
    'application_fee_amount' => $platformFee,
    'transfer_data' => [
        'destination' => $vendor->stripe_account_id,
    ],
]);

The application_fee_amount stays with your platform. The remainder transfers to the vendor’s connected account automatically.

Handling Webhooks

Webhooks are where multi-tenant Stripe gets complex. Events can come from your platform account or from connected accounts, and you need to handle both.

Always verify the webhook signature. For connected account events, the account field in the event payload identifies which tenant triggered it.

The Subscription Layer

If your platform has its own subscription tier (vendors pay you monthly), handle that as a separate Stripe Customer on your platform account — completely decoupled from the Connect layer. Mixing the two creates accounting nightmares.

Stripe Connect is powerful, but respect the separation of concerns. Platform billing lives on your account. Marketplace transactions flow through Connect.