Stripe Connect in Real Marketplace Flows

January 18, 2026 (6mo ago)

Stripe Connect in a marketplace is not a checkout integration. It is a lifecycle system for connected accounts, customer charges, platform fees, payouts, refunds, and compliance states that change independently over time. Production reliability comes from owning those states in your database and treating Stripe events as inputs, not as your source of truth.

What is Stripe Connect for marketplaces?

Stripe Connect lets a platform collect payments from customers and move funds to sellers, creators, or service providers. The platform usually keeps a fee. In Direct charges, destination charges, and separate charges-and-transfers models, the hard part is the same: account onboarding can be incomplete, payouts can be delayed, refunds can require transfer reversals, and webhooks can arrive more than once.

If you only store Stripe object IDs and rebuild business meaning from the API on every request, you will lose track of partial states. Keep an explicit domain model for account status, payment intent outcomes, transfer status, and reconciliation jobs.

Core design choices that hold up

  1. Keep payment and payout states explicit in your own database.
  2. Treat webhook handlers as idempotent.
  3. Separate customer billing flow from provider payout flow.
  4. Make reconciliation a first-class background process.
  5. Block checkout for accounts that are not payout-ready.

Customer-facing success ("card charged") is not the same as seller-facing success ("funds available and transferable"). Modeling those as one boolean is how marketplaces create support tickets.

How should webhook handling work?

Webhook handling should start with durable storage, then processing. Persist every event with event_id, type, received_at, processed_at, and status before side effects. Deduplicate on event_id. Process with a deterministic operation key such as transfer:{stripe_transfer_id}:create so retries cannot create duplicate transfers.

Do the minimum work in the HTTP handler: verify the signature, write the event row, enqueue a job, return 200 quickly. Heavy work belongs in workers with retries, backoff, and dead-letter visibility.

What helped most in production

  • A durable event table keyed by Stripe event_id.
  • Retry-safe handlers using deterministic operation keys.
  • Queue workers for non-blocking side effects such as emails, CRM updates, and ledger posts.
  • Monitoring for delayed payouts and mismatched transfer amounts.
  • Explicit "onboarding incomplete" states that hide sellers from checkout until requirements are met.
  • A nightly reconciliation job that compares local transfers and balances against Stripe.

Failure modes that usually appear

  • Duplicate webhook deliveries causing duplicate state transitions.
  • Connected accounts partially onboarded but still selectable in checkout.
  • Refund logic that charges the customer reverse path but does not reverse platform transfers.
  • Assuming charge.succeeded means the seller can be paid immediately.
  • Silent webhook endpoint failures after a deploy changes the signing secret or URL.
  • Mixing destination charges and separate transfers without documenting fee and tax implications.

A practical implementation checklist

  • Choose one Connect charge pattern and document why.
  • Store connected account capability flags locally and refresh them from account events.
  • Gate marketplace listing and checkout on capability, not only on "account created".
  • Write refund and dispute handlers that know how to reverse or claw back transfers.
  • Alert on queue lag, failed webhook processing, and payouts stuck beyond a threshold.
  • Keep an admin view of account, payment, transfer, and reconciliation status for support.

How do you reconcile marketplace money safely?

Reconciliation means comparing what your database believes happened with what Stripe reports. Run it on a schedule, not only when a customer complains. Compare payment intents, charges, transfers, refunds, and payout objects against local rows. Flag mismatches with enough context for a human to act: object IDs, amounts, currencies, and the last known local status.

For subscriptions or recurring marketplace fees, also track invoice state separately from transfer state. A paid invoice can still leave a seller unpaid if the transfer step failed. That gap is exactly where support volume grows.

When should you redesign instead of patch?

Patch when a single handler is wrong or a missing status gate lets incomplete accounts into checkout. Redesign when payment success, seller payout, refunds, and disputes are encoded as ad hoc flags with no event history. If nobody can answer "what is the source of truth for this seller's balance?" without opening Stripe Dashboard, the model is not production-ready yet.

Production payment systems are mostly about safe state transitions and clear observability, not just API calls. If you need help designing or repairing Stripe Connect marketplace flows, that is one of the systems I build and fix for clients.