← Stripe
Guide

How to build a Stripe Connect marketplace in .NET

By Alastair Murdoch Last reviewed Tested on Stripe Connect Express accounts · Stripe .NET library 43 · .NET 8
In short

Let Stripe host merchant sign-up, and treat a merchant as ready only when Stripe confirms payments and payouts are both switched on with nothing outstanding. Your platform creates each payment, passes the merchant their share and keeps its fee as the money moves. Refunds come back out of the merchant's share, while your fee stays with you.

4
Payment channels on one payment model
3
Merchant readiness states
6
Stripe notification endpoints, live and test
517
Commits on the platform

Before you start

  • ✓A Stripe platform account with Connect switched on, in test mode
  • ✓Your fee model written down: what you charge on each payment channel
  • ✓A decision on how payments are structured (who the payment is created on) before any build starts
  • ✓A way to receive Stripe's event notifications while testing

Choosing the account type and payment model

On Paypolli we run Stripe's Express accounts with destination charges: Stripe hosts merchant sign-up and the merchant dashboard, your platform creates every payment, and your fee is taken as the money moves. We've also built a product where payments are created on the merchant's own account (direct charges). It works, but every later step must then name the merchant's account, and missing one fails in ways testing rarely catches. Our ticketing marketplace guide covers when that model fits.

Signing merchants up

Each merchant gets a Stripe account able to take card payments and receive transfers, and Stripe's hosted sign-up collects their details. Sign-up links expire, so an expired link should quietly produce a fresh one, not an error.

Deciding when a merchant is ready

Finishing sign-up doesn't mean a merchant can trade. We read their status from Stripe's account notifications, with three states rather than two:

  • Complete: payments and payouts on, details submitted, nothing due now or later.
  • Needs attention: working, but Stripe wants something. Tell the merchant before it becomes a block.
  • Has issues: anything else. Don't take payments for them.

Taking payments and setting fees

Every payment names the merchant as the business being paid and the recipient of the money, and carries your fee. On Paypolli that holds on all four channels: card readers and Tap to Pay, card-not-present, hosted checkout and payment links.

Fees are worked out in whole pence with every part rounded up: your processing cost, your margin, and a surcharge for the channel. Automated tests pin this down at the edges, where a penny either side of a rounding boundary should change the fee exactly as intended.

Refunds

A refund pulls the merchant's share back from them while your fee stays with you. Each refund carries a unique reference so a retry can't refund twice, and a refund that's later cancelled or fails puts the amount back.

Notifications you can trust

  • Separate endpoints for merchant, platform and reporting events, in live and test: six on Paypolli.
  • Check every notification genuinely came from Stripe, and make sure a Stripe library upgrade can't break how they're read.
  • Assume every event arrives twice, and make the second copy harmless.

What usually goes wrong

From our own projects, not the manual.

Payments went out in the wrong currency

The code used the platform's own currency instead of the merchant's. Always charge in the currency of the merchant's Stripe account.

Merchants' net totals came out too low

Card reader charges were subtracted twice when working out what the merchant received. Test the net figure end to end, not just the fee.

Fees stack up on in-person payments

Tap to Pay adds Stripe's own per-transaction cost on top of the card fees, so the Tap to Pay surcharge had to rise to recover it. Work out each channel's real cost before setting its fee.

Failed card checks created phantom transactions

Each failed 3D Secure attempt on the same payment produced its own charge record. We de-duplicate on the latest charge, not the payment.

A double-click took two payments

A card-not-present form submitted twice and created two charges. Give each form a unique reference so a repeat is ignored, and disable the button once it's pressed.

Stripe notifications failed on refunds without a note

The handler expected a refund note that isn't always there, and returned an error. Never assume optional details are present.

Do it yourself, or get help?

If you're building a straightforward marketplace and your developers are comfortable with Stripe's event notifications and safe retries, Stripe's Connect documentation will get you a long way. If money moves between several parties, your fees need to recover real processing costs, or you're taking in-person payments too, get help early: payment-model and fee decisions are expensive to change once merchants are live.

Get a developer on it
FAQ

Common questions

What's the difference between destination and direct charges?

With destination charges your platform creates the payment and Stripe passes the merchant's share on, minus your fee. With direct charges the payment is created on the merchant's own account, and everything that follows has to name that account.

When is a connected account ready to take payments?

When payments and payouts are switched on, their details are submitted, and nothing is due now or later. Read that from Stripe's account update notifications, not from the merchant reaching the end of sign-up.

How do I refund without losing my platform fee?

Refund so that the merchant's share is taken back from them but your application fee isn't refunded. The customer gets their money back and your fee stays with you.

How many webhook endpoints do I need?

We use separate endpoints for merchant account, platform and reporting events, each in live and test. That way each has its own secret and can be retried independently.

Building a marketplace on Stripe?

Tell us who pays whom and how you charge. We'll design the Connect set-up and build it properly.