Your App LogoYOUR APP EXPERTYAE
    • Services
    • About
    • Portfolio
    • Blog
    • FAQ
    • Build Your App
    1. Home
    2. Blog
    3. Stripe Connect marketplace architecture: a deep dive
    Payments

    Stripe Connect marketplace architecture: a deep dive

    How to architect a multi-sided marketplace on Stripe Connect — Express vs Standard accounts, fund flows, the fee model, and the parts most teams build wrong.

    YAEL Engineering·03 Dec 2025·9 min read·1,770 words
    On this page
    • The three account types — and the choice that defines everything
    • Fund flow — the two patterns you can choose between
    • Direct charge
    • Destination charge
    • Separate charges and transfers
    • Which fund flow when
    • Onboarding flow with Express
    • The capabilities model
    • Disputes and chargebacks
    • Refunds
    • Multi-currency and cross-border
    • The platform-fee model
    • Reconciliation — the part nobody mentions
    • FAQ
    • Can I switch from Express to Custom later?
    • What's the Stripe fee for Connect?
    • Do I have to handle 1099-K filings?
    • Can sellers be individuals or only businesses?
    • What about payouts to non-Stripe-supported countries?
    • Should I use Stripe Issuing for spending controls?
    • How long does Express onboarding take?
    • Can I escrow funds for arbitrary durations?

    Stripe Connect is the default infrastructure for any marketplace where money flows between users (buyers and sellers, customers and creators, riders and drivers). It is also the only Stripe product where picking the wrong sub-mode early — Standard vs Express vs Custom — can force a painful migration later. The right answer depends entirely on how much of the seller experience you want to own, how much KYC liability you want to take on, and whether your sellers are full businesses or one-off individuals. We've built marketplaces in every flavor of Connect. This is the architecture decision framework — and the parts the docs leave you to figure out.

    The three account types — and the choice that defines everything

    Stripe Connect has three account flavors. They differ in who owns the seller relationship, who handles KYC, and what UI you build.

    | | Standard | Express | Custom | |---|---|---|---| | Seller dashboard | Stripe's | Stripe's (minimal) | Yours | | KYC | Stripe handles end-to-end | Stripe handles, in your branded onboarding | You handle | | Disputes | Sellers handle via Stripe | Stripe handles | You handle | | Fees you pay to Stripe | 0.25% + $2/month per active account | 0.25% + $2/month per active account | Higher (~0.4-1%) | | Effort to integrate | Lowest | Medium | Highest | | Best for | Empowered business sellers | Most marketplaces | Tightly controlled or regulated |

    The most common right answer is Express. It gives you a branded onboarding flow, Stripe handles all the KYC/compliance complexity, and your sellers get a minimal Stripe-hosted dashboard for payouts.

    The second-most common right answer is Custom, when you absolutely need to control the entire experience and you have the engineering to handle disputes, KYC re-verification, and edge cases.

    Standard makes sense when your sellers are sophisticated businesses who already use Stripe and want their own dashboard. Rare for new marketplaces.

    Fund flow — the two patterns you can choose between

    When a buyer pays $100 in your marketplace, where does the money go? Two patterns.

    Direct charge

    The charge is made directly on the connected account. The seller is the merchant of record. You take a platform fee via application_fee_amount.

    ts
    const charge = await stripe.paymentIntents.create({
      amount: 10000,
      currency: "usd",
      payment_method_types: ["card"],
      application_fee_amount: 500, // your $5 platform fee
      transfer_data: {
        destination: connectedAccountId,
      },
    }, {
      stripeAccount: connectedAccountId, // direct charge on the connected account
    });

    Money goes straight to the seller's Stripe balance, minus your fee and Stripe's fee. The seller sees the customer on their statement.

    Destination charge

    The charge is made on your platform account. You then transfer the seller's share to their connected account.

    ts
    const charge = await stripe.paymentIntents.create({
      amount: 10000,
      currency: "usd",
      payment_method_types: ["card"],
      application_fee_amount: 500,
      transfer_data: {
        destination: connectedAccountId,
      },
    }, /* no stripeAccount option — this is on YOUR platform */);

    Money goes to your balance first; Stripe automatically transfers the seller's portion.

    Separate charges and transfers

    Most flexibility. You charge on your platform account, then manually transfer to the seller's account whenever you want — after delivery confirmation, after an escrow window, after dispute resolution.

    ts
    // Step 1: charge the buyer (money sits on your platform)
    const charge = await stripe.paymentIntents.create({
      amount: 10000,
      currency: "usd",
    });
    
    // Step 2: later, transfer to seller
    const transfer = await stripe.transfers.create({
      amount: 9500,
      currency: "usd",
      destination: connectedAccountId,
      source_transaction: charge.latest_charge,
    });

    For escrow-style marketplaces (Airbnb, Fiverr), this is the right pattern. The buyer's money sits on your platform until the work is delivered, then you trigger the transfer.

    Which fund flow when

    • Direct charge — sellers want to feel "in control" of the relationship. You're a directory + matching layer.
    • Destination charge — most marketplaces. Buyers pay you; you pay sellers a slice automatically.
    • Separate charges and transfers — when you need escrow, holdback, or any delay between buyer payment and seller payout.

    We default to destination charge for most marketplaces. Switch to separate charges and transfers when escrow matters.

    Onboarding flow with Express

    The flow most marketplaces ship:

    1. Seller signs up on your platform.
    2. You create an Express account: stripe.accounts.create({ type: "express", country, email }).
    3. You generate an onboarding link: stripe.accountLinks.create({ account, refresh_url, return_url, type: "account_onboarding" }).
    4. You redirect the seller to the link. They go through Stripe's branded KYC flow.
    5. On return, you check account.charges_enabled and account.payouts_enabled.
    ts
    // Step 1 — create the connected account
    const account = await stripe.accounts.create({
      type: "express",
      country: "US",
      email: seller.email,
      capabilities: {
        card_payments: { requested: true },
        transfers: { requested: true },
      },
    });
    
    // Step 2 — generate onboarding link
    const link = await stripe.accountLinks.create({
      account: account.id,
      refresh_url: `${origin}/sellers/onboarding/refresh`,
      return_url: `${origin}/sellers/onboarding/complete`,
      type: "account_onboarding",
    });
    
    return redirect(link.url);

    Crucially: the seller may abandon partway through KYC and never come back. Your webhook handler must listen for account.updated and check the charges_enabled field whenever it changes. Don't trust the return_url as the signal that KYC is complete.

    The capabilities model

    Each Express account has "capabilities" — card_payments, transfers, legacy_payments, etc. Each can be inactive, pending, or active. A seller cannot receive payments until both card_payments and transfers are active.

    This is the source of most marketplace bugs. A seller completes onboarding but charges_enabled is still false because Stripe is verifying their bank account. The buyer tries to pay; the charge succeeds but the transfer fails; you have orphaned money on your platform.

    Mitigation: don't allow a buyer to check out with a seller whose charges_enabled is false. Run a daily sync that updates seller state in your DB. Surface "your onboarding is incomplete" prominently in the seller dashboard.

    Disputes and chargebacks

    In direct-charge mode, the seller handles disputes via their Stripe dashboard. They submit evidence; Stripe arbitrates; the seller eats the chargeback fee if they lose.

    In destination-charge mode, you handle disputes by default. The seller has no Stripe dashboard for it. You either expose dispute management in your UI or eat the disputes silently. Most marketplaces underbudget for this.

    Decision: who absorbs the chargeback?

    • The seller (recover the disputed amount from their next payout — Stripe automates this with the liability_holder setting)
    • The platform (you eat it, charge it to your margin)
    • Split with insurance / a reserve fund

    There's no right answer. The wrong answer is not deciding until your first chargeback lands.

    Refunds

    Refunds reverse the original charge. In destination-charge mode you can either:

    • Refund only the buyer-facing amount; the platform fee comes out of your platform balance (default)
    • Reverse the transfer as well; the seller's portion is pulled back from their balance
    ts
    // Refund the buyer AND pull back the seller's share
    await stripe.refunds.create({
      payment_intent: paymentIntentId,
      reverse_transfer: true,
    });

    Decide your refund policy carefully. "Customer gets a refund and the seller keeps their fee" creates a fraud vector — buyer + seller collude, buyer disputes, seller keeps the money. "Customer gets a refund and the seller's payout is reversed" is the safer default.

    Multi-currency and cross-border

    The hardest part of marketplace ops. Sellers in 30 countries, buyers in 40 countries, currencies all over.

    Stripe Connect supports cross-border payouts in many country pairs but not all. You need to maintain a country-pair compatibility table. Some pairs require currency conversion; some require local entity registration.

    For complex marketplaces this is a real engineering project. For a US-only marketplace it's a non-issue. Plan accordingly.

    The platform-fee model

    A few common patterns:

    • Take rate (a percentage of every transaction) — most common, easiest
    • Subscription (sellers pay a monthly fee, no take rate) — better for high-volume sellers, worse for occasional sellers
    • Hybrid (low take rate + a sub option that removes it) — best of both, more complex billing

    Decide early. Changing the take rate later is fine; switching models is a billing migration.

    Reconciliation — the part nobody mentions

    At the end of every day, you should be able to answer: how much did every seller earn yesterday? How much did the platform earn? Does our database match Stripe's reality?

    Build the reconciliation job from day one. It's a periodic sync that:

    1. Pulls Stripe's transfers for the previous day per connected account
    2. Compares to your DB's expected transfers
    3. Alerts on any mismatch
    ts
    async function reconcileDay(date: Date) {
      for (const seller of activeSellers) {
        const stripeTransfers = await stripe.transfers.list({
          destination: seller.stripeAccountId,
          created: { gte: dayStart(date), lte: dayEnd(date) },
        });
        const dbTransfers = await db.transfers.findMany({
          where: { sellerId: seller.id, createdAt: { gte: dayStart(date), lte: dayEnd(date) } },
        });
        if (sum(stripeTransfers) !== sum(dbTransfers)) {
          await alert("seller_reconciliation_mismatch", { sellerId: seller.id });
        }
      }
    }

    You'll thank us when the first audit hits.

    Building a marketplace on Stripe Connect?

    We've shipped Connect-powered marketplaces with custom fund flows, escrow, multi-currency, and the reconciliation infra most teams skip.

    See Stripe service

    FAQ

    Can I switch from Express to Custom later?

    Not easily. The seller accounts are tied to the account type. You can migrate but it requires re-onboarding each seller. Pick deliberately.

    What's the Stripe fee for Connect?

    On Express/Standard: 0.25% + $2/month per active account. On Custom: higher, varies. Plus the regular Stripe processing fee (2.9% + $0.30) on every transaction. Plus your platform fee on top.

    Do I have to handle 1099-K filings?

    In the US, yes — for sellers earning above the threshold. Stripe Tax (which integrates with Connect) can automate it. Worth turning on early.

    Can sellers be individuals or only businesses?

    Both. Stripe handles individual KYC (SSN, address verification) and business KYC (EIN, beneficial ownership) within the Express flow.

    What about payouts to non-Stripe-supported countries?

    You can't pay them via Stripe Connect. Workarounds: Wise/Payoneer integration on top, or PayPal Mass Payments. Both are real engineering. If your seller mix is global, model this carefully.

    Should I use Stripe Issuing for spending controls?

    Stripe Issuing is for the platform issuing cards to sellers. Useful if sellers need to spend marketplace funds (e.g. Uber issues driver cards). Most marketplaces don't need it.

    How long does Express onboarding take?

    5-15 minutes for the seller, then 0-24 hours for Stripe's automated KYC. Edge cases (sole props with unusual documents) can take days.

    Can I escrow funds for arbitrary durations?

    Yes, with separate charges and transfers — money sits on your platform balance until you initiate the transfer. Be aware of regulatory limits: in some jurisdictions, holding customer money for too long triggers money-transmitter licensing requirements.

    TagsStripe ConnectMarketplacesPaymentsArchitecture
    ServiceStripe IntegrationSaaS Development
    PreviousSelf-hosting Llama vs Claude API: the real cost breakdownNext Choosing a vector database: pgvector vs Pinecone vs Qdrant

    Keep reading

    PaymentsStripe Billing vs Paddle vs LemonSqueezy for SaaS in 2026An opinionated comparison of the three default billing platforms for B2B SaaS — pricing model coverage, MoR vs not, dev DX, and where each one breaks at scale.8 min readSaaSHow to build a SaaS MVP in 6 weeks (without a rewrite later)A six-week SaaS MVP plan that doesn't trade speed for technical debt — auth, billing, multi-tenancy, and a real operator dashboard from day one.10 min readBots & MessagingTelegram bot payments with Stripe: the production integration guideHow to wire Stripe into a Telegram bot the right way — invoice flows, webhook idempotency, refund handling, and the parts the docs don't tell you.8 min read
    On this page
    • The three account types — and the choice that defines everything
    • Fund flow — the two patterns you can choose between
    • Direct charge
    • Destination charge
    • Separate charges and transfers
    • Which fund flow when
    • Onboarding flow with Express
    • The capabilities model
    • Disputes and chargebacks
    • Refunds
    • Multi-currency and cross-border
    • The platform-fee model
    • Reconciliation — the part nobody mentions
    • FAQ
    • Can I switch from Express to Custom later?
    • What's the Stripe fee for Connect?
    • Do I have to handle 1099-K filings?
    • Can sellers be individuals or only businesses?
    • What about payouts to non-Stripe-supported countries?
    • Should I use Stripe Issuing for spending controls?
    • How long does Express onboarding take?
    • Can I escrow funds for arbitrary durations?

    YOUR APP EXPERT LTD

    71-75 Shelton Street, LONDON WC2H 9JQ, UK

    +44 20 1234 5678

    [email protected]

    Quick Links

    • Services
    • About Us
    • Portfolio
    • Blog
    • Contact

    Stay Connected

    Newsletter

    Stay updated with our latest innovations and insights.

    © 2026 YOUR APP EXPERT LTD. All rights reserved.

    Engineering the Future of Technology