I went into Fresha's documentation expecting to find connected accounts. I found a wallet.
That single discovery reframes the whole category. The assumption most people start from is that clinics and salons are independent businesses, so obviously each one must be its own merchant on the platform's payment rails. Fresha decided otherwise. Fresha's own payments documentation states that "all payments are securely collected into your business wallet", with next-day payouts from that wallet out to a bank account, and instant routing between team members when a sale is split. Money pools at the platform first. It leaves later.
I made the opposite call on a clinic SaaS, and I want to be honest that it was a call rather than an obvious answer. Every marketplace built on Stripe Connect eventually hits the same question: direct charges or destination charges, whose balance does the money actually land in. It is the one architectural decision you cannot refactor cheaply once real merchants are live on it.
What Fresha's payment stack does with the money

Fresha operates a pooled wallet: the platform collects, holds briefly, and pays out, rather than settling each sale into the salon's own merchant account.
The published numbers tell you why that shape exists. Fresha's 2026 pricing page lists online payments at 2.79% + $0.20 per transaction, in-person at 2.29% + $0.20, manual card entry at 3.30% + $0.20, and subscriptions at $19.95 per month for an independent or $14.95 per team member for a team. Then the interesting line: a 20% one-time commission, minimum $6, on new clients who arrive through the Fresha marketplace, and nothing on returning clients.
Look at what that commission requires. To bill a percentage of a booking that a salon received because Fresha sent the customer, the platform has to be sitting in the flow of funds at the moment the money moves. A wallet does that. So does an automatic sales split across three stylists on one ticket. Neither is impossible if every salon is its own settlement merchant, but both get considerably more awkward, because you are now reaching into somebody else's balance to take your cut.
The topology is not an implementation detail underneath the business model. It is the business model, expressed in ledger entries.
Direct charges or destination charges: whose balance holds the money?

Direct charges land the payment in the connected account's balance; destination charges land it in your platform's balance, and refunds and disputes follow the money.
Everything else is downstream of that sentence. Stripe's documentation on Connect charge types puts it plainly: the charge type "determines whether your platform's or the connected account's information appears on the customer's bank or billing statement and which account Stripe debits for refunds and chargebacks." Two consequences, one decision, and both of them are legal as much as technical.
| Direct charges | Destination charges | Separate charges and transfers | |
|---|---|---|---|
| Payment lands in | Connected account's balance | Platform's balance | Platform's balance |
| Customer perceives | The merchant; often unaware your platform exists | Your platform's brand | Your platform's brand |
| Refunds and chargebacks debit | Connected account | Platform | Platform |
| Stripe fees billed to | Platform or connected account, your choice | Platform | Platform |
| Stripe's recommended negative-balance owner | Stripe | Platform | Platform |
| Stripe's own example | A SaaS platform, such as an accounting product that enables invoice payments | A branded service using independent contractors, such as a rideshare app | A cart split across multiple sellers, such as a delivery marketplace |
Read the bottom row again, because Stripe is describing two different companies, not two different code paths. A rideshare app owns the customer relationship; the driver is interchangeable. An accounting platform does not own the invoice; the accountant's client is paying the accountant. Which of those two companies is yours? If you cannot answer that in one sentence, you are not ready to write the integration yet.
One detail that catches people: with direct charges, funds always settle in the country of the connected account. For a platform selling across borders, that is either exactly what you want or a tax problem you discovered late.
Which topology should a booking platform pick?

Pick direct charges when each merchant is the legal seller of record; pick destination charges when your own brand is what the customer bought.
That test sounds abstract until you apply it to a regulated service. Here is the sequence I would work through before writing any Connect code:
- Name the merchant of record for the underlying service, meaning the treatment or appointment itself rather than the software that scheduled it. If a practitioner injects a patient and something goes wrong, whose insurance, whose licence, whose registration is on the line? That party should hold the money.
- Ask who the customer thinks they are paying. Check the booking confirmation, the statement descriptor, the refund email. If the answer is "the clinic", direct charges keep the story consistent end to end.
- Decide whether you need to split one payment across several parties. Multi-practitioner commission splits push you toward separate charges and transfers, because that is the only topology built for a one-to-many payout.
- Check whether your commercial model requires taking a cut of transactions you did not originate. A marketplace acquisition fee, like Fresha's 20% on new clients, is far easier when funds pass through you.
- Confirm you can live with the dispute posture. Under direct charges Stripe debits the connected account's balance for a chargeback. That is a feature if the merchant is genuinely liable, and a support nightmare if they think you are their bank.
Work those five in order and the answer usually falls out before step four. Work them backwards, starting from "which one is easier to build", and you will pick correctly by accident about half the time.
Direct charges are not a liability firewall
Worth killing this belief early. Direct charges do not make a disputed payment somebody else's problem by definition. Stripe's fee-payer documentation shows that where the disputed amount cannot be recovered from the connected account, responsibility follows negative-balance liability, and dispute fees follow the fee-collector setting independently. Same charge type, four possible outcomes.
What I shipped on Callidus, and what I would check again
I built Callidus OS, a multi-tenant clinic SaaS for UK aesthetic clinics, on Stripe Connect Standard with direct charges, one Connect account per clinic, and a 0.1% application fee on patient deposits collected through the embeddable booking widget. The reasoning was step one of that list and nothing else. Each clinic is the legal merchant of record for the medical services it performs, so pooling deposits into the platform's account would have moved liability in precisely the wrong direction. A software company does not want to be the counterparty on a cosmetic procedure.
The webhook that taught me the most was invoice.payment_action_required. It fires when a renewal needs 3D Secure and nobody is in the room to tap approve, which on a clinic's billing date usually means the subscription silently fails at some hour when the practice is closed. Handling it properly meant catching the event, escalating, and emailing the owner the hosted invoice URL so the recovery path was one tap rather than a support ticket. Twenty webhook events across the subscription lifecycle, and that is the one I would wire first on a rebuild.
Actually, let me back up, because there is a nastier lesson in that same surface. ANNUAL_PRICE_IDS exists in that codebase as an explicit allowlist that blocks promo codes on annual plans, and it exists because a 100%-off coupon applied to an annual price is a free year, not a free month. You find that class of bug by reading your own price objects adversarially, not by testing the happy path.
If you are sizing a build like this, most of the cost is not the payment integration. It is the six-role access matrix and the tenant isolation underneath it. I have written separately on what multi-tenant SaaS actually means for data isolation, and there is a rough app cost estimator if you want a number before you scope anything.
Stripe deprecated the account types this pattern is built on
Standard, Express and Custom are now labelled legacy. Stripe's integration recommendations page describes them as "Legacy connected account types (Standard, Express, and Custom): (deprecated)" and recommends the Accounts v2 API for new integrations, with existing platforms pointed at a migration path. The charge-type semantics have not changed. What changed is the object you create to hold them, and the vocabulary: controller.fees.payer on v1 becomes defaults.responsibilities.fees_collector on v2.
One line in that documentation deserves more attention than it gets. You can specify the fee payer only when you create an account. There is no later, and no support ticket that reopens it. Whatever you decide about who absorbs Stripe's processing fees is baked in at account.create for every merchant you have already onboarded, which means a pricing change eighteen months in can require re-onboarding your entire book. Ask me how confident I am that most platforms know this before their hundredth connected account.
If you want the shorter version of how these pieces fit together commercially, I keep a plain-language explainer on what a Stripe integration involves for people scoping a build rather than writing one.
So before you open the Connect dashboard: go and find the indemnity clause in your merchant terms, then open docs.stripe.com/connect/charges next to it, and check that the two documents agree about who is liable when a customer disputes a charge. If they disagree, which one is your payment topology actually implementing?
