Marketplace Payments Architecture: Split Payments, Payouts, Escrow and KYB for Connected Accounts (2026)

Marketplace Payments Architecture: Split Payments, Payouts, Escrow and KYB for Connected Accounts (2026)

Marketplace Payments Architecture: Split Payments, Payouts, Escrow and KYB for Connected Accounts (2026)

Most marketplaces start with a single line of code: charge the buyer, pay the seller later. Eighteen months in, that line has become a tangle of fee tables, hold rules, refund exceptions, negative seller balances and a finance team reconciling three bank statements by hand. The root cause is almost never the payment processor. It is that nobody designed the marketplace payments architecture as a system with explicit money-flow models, a ledger of record, and a lifecycle for every connected account.

This matters more in 2026 than it did five years ago. Real-time rails are widespread, regulators are tightening the commercial agent exclusion, and sellers expect instant payouts while platforms still have to survive chargebacks that arrive months later. A design that cannot hold money safely, split it exactly, and unwind it cleanly will leak margin or, worse, break licensing assumptions.

This article gives you the reference design: who is liable under each charge model, how money moves through authorize, capture, hold and payout, how to model it in a double-entry ledger, and how to onboard and screen sellers. It ends with runnable Python for integer-safe fee splits.

What this covers: money-flow models, funds-flow timeline, ledger accounts, escrow and delayed payouts, KYB tiers, fee splitting and rounding, refunds and negative balances, payout rails and returns, reconciliation, and the regulatory perimeter. This is systems analysis, not legal or investment advice.

Context and Background

A marketplace is a three-sided money problem: a buyer pays, a seller earns, and the platform takes a cut while carrying risk. Everything difficult about marketplace payments comes from the fact that these three parties have different timelines. The buyer pays in seconds, the card network settles in days, the seller expects payment when the service is delivered, and the buyer can dispute the charge for months afterward.

Historically, platforms solved this by collecting everything into their own bank account and wiring sellers manually. That makes the platform a custodian of other people’s money, which in most jurisdictions pulls it toward money transmission or e-money regulation. The modern alternative is to build on a licensed payment service provider (PSP) that offers a connected-account model. Stripe Connect is the best-documented example, and Adyen for Platforms, PayPal Commerce Platform, Mangopay, Checkout.com and Airwallex offer comparable constructs under different names. The concepts transfer even where the vocabulary does not.

In a connected-account model, each seller is a first-class legal and financial entity inside the PSP, with its own balance, its own verification status and its own external bank account. The platform keeps its own account and moves money between itself and sellers through documented primitives: charges, transfers, application fees and payouts. Stripe’s Connect documentation describes the three charge types this way: direct charges, destination charges, and separate charges and transfers, and it explicitly says the type you choose determines whose balance is debited for refunds and chargebacks. That one sentence is the most consequential design decision in the whole stack.

The PSP does not remove your engineering burden. It removes the licensing burden for holding funds and the card-scheme integration burden, but you still own the product logic: when a seller is allowed to be paid, how fees are computed, what happens when a refund exceeds a seller’s balance, and how you prove to an auditor that every cent is accounted for. For the ledger side of that proof, see our guide on double-entry ledger database architecture. For the PSP routing layer that sits above it, see payment orchestration platform architecture.

Two ideas run through the rest of this post. First, the PSP’s balance is a processor view; your ledger is the business view, and the two must reconcile but never be confused. Second, every state transition in a marketplace payment is a place where money can be duplicated or lost, so each must be idempotent and recorded as balanced journal entries.

Reference Architecture: Money-Flow Models and the Funds Timeline

In short: a marketplace picks a charge model (direct, destination, or separate charges and transfers) that decides whose balance absorbs refunds and disputes, then layers a ledger, a hold-and-release policy, and payout orchestration on top. The charge model is the load-bearing choice; everything else is policy on top of it.

Marketplace payments architecture: direct, destination and separate charge models and where refund and dispute liability lands

Figure 1: The three connected-account charge models. The branch the buyer’s payment takes decides which balance absorbs refunds and disputes.

Figure 1 shows the structural difference. In a direct charge the payment is created on the seller’s account, so it lands in the seller’s balance, and the platform receives an application fee. In a destination charge the payment is created on the platform and a portion is immediately transferred to one seller. In separate charges and transfers the platform charges first and transfers later, possibly to several sellers, possibly before it even knows who they are. The diagram makes the liability visible: the left branch loads risk onto the seller, while the right two branches load it onto the platform balance.

Direct charges: the seller is the merchant

Under direct charges, according to Stripe’s documentation, the payment appears in the connected account’s balance, funds settle in the connected account’s country, and refunds and chargebacks reduce the connected account’s balance. The platform’s balance increases only by the application fee. Stripe positions this model for software platforms whose sellers deal directly with their own customers, such as storefront or course-selling tools.

The architectural upside is that the platform is not exposed to seller-level losses by default, and the seller appears on the buyer’s statement. The downside is that the platform has little control over the transaction: it cannot easily split one cart across several sellers, and the customer relationship belongs to the seller. Direct charges also require the seller account to carry the card-payments capability, which pushes more verification work onto onboarding.

Destination charges: the platform is the merchant

With destination charges the platform creates the charge, a portion transfers to the connected account, and what remains in the platform balance is the fee. Refunds and chargebacks debit the platform balance, and processing fees are billed to the platform. This is the natural fit for a branded marketplace: the buyer thinks they are buying from the platform, and each order maps to exactly one seller.

The on_behalf_of parameter changes the picture in a specific way. It makes the connected account the business of record, so settlement happens in that account’s country, its fee structure applies, and its statement descriptor is used. This reduces declines and currency conversion for cross-border sellers, but it also increases the seller-facing footprint of the transaction, which matters for the regulatory discussion later.

Separate charges and transfers: the platform is a router

When one cart contains items from several sellers, or you charge before knowing who fulfils the order, you need the charge and the transfer to be decoupled. Stripe lists the use cases directly: one-to-many splits, many-to-one pooling, charging before the destination is known, transferring before the payment lands, and transfers that exceed the associated payment. The platform’s balance is debited for fees, refunds and chargebacks, and you can link a transfer to a source charge so it does not execute until those funds are available.

Decoupling buys flexibility and costs correctness risk. Stripe notes that you must monitor your balance so transfers do not exceed available funds, and that failed transfers between platform and connected balances are not retried automatically. That second sentence deserves attention: a transfer that fails because the platform balance was momentarily insufficient will stay failed until your code retries it. A marketplace that does not model transfers as durable, retryable jobs will silently under-pay sellers.

Choosing a model

A practical heuristic is to start from the question “who do we want the dispute to land on?” If the answer is the seller and your product is software, use direct charges. If you sell a branded service and one order maps to one seller, use destination charges. If carts span sellers, if you need to hold funds before assigning a recipient, or if the payout amount differs from the payment amount, use separate charges and transfers. Many platforms mix: destination charges for the common path, separate charges for multi-vendor carts. The ledger must handle all of them with the same account structure, which is why the ledger comes before the integration.

The funds timeline

Whatever the model, money follows the same life cycle, shown in Figure 2.

Sequence diagram of marketplace payments funds flow from authorization through capture, hold, release and payout

Figure 2: Funds timeline from checkout to payout. The hold between “funds available” and “release transfer” is the platform’s policy window, and the return path after the payout is the rail’s.

Authorization reserves the buyer’s credit limit but moves no money. Capture instructs the network to settle. After capture, Stripe’s balance documentation says charged funds first appear as pending, then become available on a rolling basis that is typically two days but varies by country and account. Only available funds can be paid out. The platform then decides whether to release funds immediately or hold them until a precondition is met, typically delivery confirmation, check-in, or the end of an inspection window.

The key insight is that there are two independent clocks. The PSP controls when funds become available. The platform controls when funds are released to the seller. Payout then runs over a rail with its own latency and its own return window. A good design makes each clock explicit in the data model, with timestamps for captured, available, released and paid out, so that support and finance can answer “where is this seller’s money?” without reading logs.

Deeper Analysis: Ledger, Escrow, Onboarding, Splits and Unwinds

A double-entry ledger that matches the funds timeline

The PSP balance tells you how much money Stripe or Adyen thinks sits where. It does not tell you how much of the platform’s balance belongs to sellers, how much is your revenue, and how much is a reserve you are holding against future disputes. That decomposition is your job, and the only defensible way to do it is a double-entry ledger in which every movement is a balanced set of debits and credits.

Double-entry ledger accounts for a marketplace: escrow, seller payable, platform fee revenue, reserve and payout in transit

Figure 3: Ledger account flow. Buyer funds enter as a liability to the buyer and move to seller payable, fee revenue and reserve on release; payouts convert payable into settled bank cash.

The account structure in Figure 3 is deliberately small. A clearing asset account mirrors the PSP’s view of money it owes you. An escrow liability holds funds that have been captured but not yet released. Per-seller payable liabilities hold what you owe each seller, per-seller reserve liabilities hold the portion you have withheld as a buffer, and a revenue account holds your take. Payout-in-transit is an asset-or-liability bridge that exists between the moment you instruct a payout and the moment the bank confirms settlement.

Every real event is a journal entry. Capture debits clearing (net of PSP fees) and the PSP fee expense, and credits escrow for the gross. Release debits escrow and credits fee revenue, reserve and seller payable. Payout initiation debits seller payable and credits payout-in-transit; settlement debits payout-in-transit and credits the bank asset. A refund or dispute reverses part of this chain. The invariant to enforce in the database is that the debits and credits of any journal entry sum to zero, and that entries are append-only; corrections are new reversing entries, never edits. For storage patterns, concurrency and balance computation at scale, see our detailed treatment of double-entry ledger database architecture.

Two practical rules save pain later. First, give every journal entry a deterministic business key such as order_123:release:seller_9 and enforce uniqueness, so a retried worker cannot post the same release twice. This is the same principle as payment-API idempotency; see idempotency keys and exactly-once payment retries for the full protocol. Second, never let a seller’s displayed balance be a mutable counter. Derive it by summing ledger lines, optionally with a cached projection that can be rebuilt.

Fee splits, rounding and integer minor units

Money must never be floating point. Store amounts as integers in the currency’s minor unit (cents for USD and EUR, whole units for currencies such as JPY that have no minor unit, three decimals for some dinar currencies). The ISO 4217 table defines how many decimal places each currency uses, and your code should read the exponent from it rather than assuming two.

Rounding is where marketplaces quietly lose money or fail audits. Consider a EUR 100.01 cart (10,001 minor units) split across three sellers whose items total 3,334, 3,334 and 3,333. A 10 percent platform fee computed per seller and rounded half-even yields 333 on each, a total of 999, whereas 10 percent of the whole cart would be 1,000.1. Neither number is wrong; the point is that you must pick one rule, document it, and make the sum of the parts equal the total by construction. The standard technique for allocating a shared amount, such as a PSP fee or a shipping charge, across parties is largest-remainder allocation: compute each share by integer division, then hand out the leftover units one by one to the parties with the largest fractional remainders, breaking ties deterministically.

The snippet below implements the fee, the allocation and the balanced journal lines with integers only. The rates (10 percent take, 5 percent reserve, 2.9 percent plus 30 minor units PSP cost) are illustrative values chosen to make the arithmetic visible, not any provider’s price list.

from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_EVEN

def bps_fee(amount_minor: int, bps: int, fixed_minor: int = 0) -> int:
    """Fee in basis points with banker's rounding, integer minor units."""
    pct = (Decimal(amount_minor) * bps / Decimal(10_000)).quantize(Decimal(1), ROUND_HALF_EVEN)
    return int(pct) + fixed_minor

def allocate(total: int, weights: list[int]) -> list[int]:
    """Largest-remainder allocation: parts always sum exactly to total."""
    s = sum(weights)
    base = [total * w // s for w in weights]
    rem = total - sum(base)
    order = sorted(range(len(weights)), key=lambda i: (-(total * weights[i] % s), i))
    for i in order[:rem]:
        base[i] += 1
    return base

@dataclass(frozen=True)
class Line:
    account: str
    debit: int = 0
    credit: int = 0

def sale_entries(gross, items, take_bps=1000, reserve_bps=500, psp_bps=290, psp_fixed=30):
    """items maps seller_id to item total in minor units. Returns journal lines."""
    assert sum(items.values()) == gross
    psp_fee = bps_fee(gross, psp_bps, psp_fixed)
    lines = [Line("asset:psp_clearing", debit=gross - psp_fee),
             Line("expense:psp_fees", debit=psp_fee),
             Line("liability:escrow", credit=gross)]           # capture
    for seller, amt in items.items():                           # release
        fee = bps_fee(amt, take_bps)
        reserve = bps_fee(amt - fee, reserve_bps)
        net = amt - fee - reserve
        lines += [Line("liability:escrow", debit=amt),
                  Line("revenue:platform_fee", credit=fee),
                  Line(f"liability:reserve:{seller}", credit=reserve),
                  Line(f"liability:seller_payable:{seller}", credit=net)]
    return lines

def assert_balanced(lines):
    d = sum(l.debit for l in lines); c = sum(l.credit for l in lines)
    assert d == c, f"unbalanced: {d} != {c}"
    return d

if __name__ == "__main__":
    items = {"s1": 3334, "s2": 3334, "s3": 3333}   # illustrative EUR 100.01 cart
    lines = sale_entries(10001, items)
    print("balanced total:", assert_balanced(lines))
    print(allocate(100, [1, 1, 1]))                 # [34, 33, 33]

Running it on the illustrative cart yields a PSP fee of 320, seller fees of 333 each, reserves of 150 each, and seller payables of 2,851, 2,851 and 2,850. The assertion that debits equal credits holds both at capture and across the release. Notice that the PSP fee is borne by the platform in this example, as it is under destination charges and separate charges and transfers; under direct charges you would instead choose, per Stripe’s documentation, whether fees are debited from the connected account or from the platform, and the ledger lines change accordingly. The takeaway is that the ledger structure is stable while the fee-bearer is a parameter.

Escrow, holds and delayed payouts

“Escrow” is used loosely in marketplace products. In regulatory and legal terms, a true escrow involves a neutral third party holding funds under conditions agreed by buyer and seller, and in some jurisdictions that role is licensed or restricted. Operationally, most platforms implement what is better described as delayed payout: the funds are captured into the platform’s PSP balance, recorded as an escrow liability in the ledger, and released to the seller when a condition is met. The legal characterisation of that arrangement depends on contract terms and jurisdiction, so treat the word “escrow” in your UI with care and take counsel on it.

Stripe’s guidance on this is instructive. Its documentation says the typical reason to hold funds is on-demand services where the marketplace waits for the service to be completed and confirmed, and it advises against holding funds arbitrarily, recommending that platforms pay out as soon as recipients are identified. It also states that for compliance reasons funds can be held in reserve for periods that vary by country, listing 10 days for Thailand, 2 years for the United States and 90 days for other countries. Those figures describe Stripe’s own reserve holding behaviour at the time of writing and should be re-verified against current documentation before you rely on them.

The architectural implication is that a hold needs a reason code, an owner and an expiry. A hold with reason awaiting_delivery, an automatic release deadline of, say, seven days after the carrier’s delivered event, and an escalation path when a dispute opens is a policy. A hold with no expiry is a liability you have created for yourself. Implement holds as rows with a state machine (placed, released, forfeited, refunded) rather than as a boolean on the order, because buyers open disputes mid-hold, sellers get suspended mid-hold, and partial releases are common.

KYB onboarding as a tiered state machine

Sellers who are businesses require know-your-business (KYB) verification; individuals require know-your-customer (KYC). In a connected-account model, the PSP collects and verifies most of this, but the platform decides when each requirement is demanded, because every extra field costs conversion. The pattern that works is progressive, tiered onboarding, shown in Figure 4.

KYB onboarding tiers for marketplace sellers with sanctions screening and ongoing monitoring loops

Figure 4: Tiered KYB onboarding. Sellers can list and sell at low limits early, payouts are held until verification completes, and screening repeats on a schedule.

Tier 0 collects the minimum to create the account: a contact, a country and a business type. Screening against sanctions and politically-exposed-person lists runs immediately on whatever identifying data exists, because a sanctions hit must stop the flow regardless of tier. Tier 1 lets the seller list and receive orders with capped volume while payouts remain held. Tier 2 follows document and registry verification, including identification of ultimate beneficial owners (UBOs) where the law requires it, and enables full payouts.

The state machine must include a loop back from monitoring to screening. Sanctions lists change, ownership changes, and a seller that was clean at onboarding may not be clean at month nine. The Financial Action Task Force (FATF) recommendations on customer due diligence and beneficial ownership are the conceptual source for most national rules, but the operative requirements are the ones in your jurisdiction and your PSP’s contract. Platforms commonly under-engineer the “requirements due” path: the PSP will emit events when new information is required or a verification fails, and the platform must translate those into product states such as “payouts paused until you upload a document”, with deadlines, reminders and a clear way for the seller to fix the issue. An onboarding flow that ends at “account created” is half a flow.

Sanctions screening hooks belong at several points, not one: at onboarding, on any change to legal name, ownership or bank account, on a recurring schedule, and ideally at payout time for high-value or first-time payouts. A fuzzy-match hit should create a case, freeze payouts and route to a human reviewer with an audit trail; it should never silently fail open.

Refunds, chargebacks, negative balances and reserves

Money flows backward as well as forward, and the backward path is where marketplaces lose money. Stripe’s balance documentation describes the mechanics: refunds and chargebacks create negative transactions, Stripe first assigns them to the account on which the charge was made, it offsets them against future payments where it can, and a connected account’s balance can still go negative. Which party covers that negative balance depends on the account’s loss responsibility setting, exposed as losses_collector on v2 accounts or controller.losses.payments on v1, with the value stripe or application. When the platform is responsible, it is exposed to the loss.

For indirect charges the platform’s balance is debited first, and the platform may attempt recovery by reversing the transfer to the seller. If the seller has already been paid out, the reversal may fail or push the seller negative. Stripe documents that it will attempt to debit the seller’s external account when debit_negative_balances is enabled, in countries where banks support it, and that if a negative balance persists for 180 days it collects through a Connect collection transfer from the platform’s reserves. It also documents a platform-level reserve mechanism, in which a portion of the platform’s available balance is held, plus an additional three business days, while a negative seller balance is being covered.

The design response is a layered defence. Withhold a rolling reserve per seller, scaled by risk tier, which is the reserve liability in Figure 3. Delay payouts for new or high-risk sellers. Cap exposure by tracking each seller’s maximum possible clawback, roughly the sum of captured-but-still-disputable volume minus reserve. When a dispute arrives, post ledger entries that debit the seller’s reserve first, then seller payable, then a negative-balance receivable if neither suffices. That receivable is a real asset with a collection probability; write it down on a schedule instead of pretending it will be recovered.

Illustrative numbers make this concrete. Suppose a seller has sold 20,000 in the last 60 days, has been paid out for all but 5 percent held in reserve (1,000), and a fraud ring causes 4,000 of disputes. The reserve covers 1,000, leaving 3,000 on the platform as a negative-balance receivable, plus dispute fees. A 15 percent reserve would have covered 3,000 but would also have starved the seller of working capital. The tuning problem is explicit in the numbers, and every marketplace has to choose a point on that curve per risk tier.

Payout orchestration: rails, timing and returns

A payout is a request to move money from your PSP balance or your own bank account to the seller’s external account over a payment rail. Payout orchestration is the layer that chooses the rail, schedules the instruction, tracks status, and handles failure. Each rail has different speed, cost, reversibility and failure vocabulary, and a marketplace serving sellers in several countries will use several.

ACH in the United States is a batch network. Credits are cheap and slow, and ACH debits are returnable. Per the return windows summarised by Increase’s documentation, commercial-account debits can be returned within two banking days and consumer-account debits within sixty calendar days, and a returned entry can only be reinitiated within 180 days of the original settlement date. Return reason codes tell you what to do next: R01 is insufficient funds, R02 is account closed, R03 is no account or unable to locate, and R10 is a customer advising the entry was not authorized. Payout credits fail mostly through R02, R03 and similar account-validity codes, whereas the debit side that platforms use to recover negative balances fails through R01 and R10. Treat these as different workflows: an R03 on a payout means pause the seller’s payouts and ask for corrected bank details, whereas an R10 on a recovery debit means stop retrying, because repeated debits after an unauthorized claim create compliance exposure.

Real-time rails such as RTP and FedNow in the United States, SEPA Instant in the euro area, and Faster Payments in the United Kingdom settle in seconds and are irrevocable once accepted. That is excellent for seller experience and dangerous for a platform that has not finished its risk checks, because a mistaken or fraudulent instant payout cannot be recalled by the network. Per-transaction limits and participation vary by network and bank, so check current rail documentation before designing around a number. SEPA Credit Transfer is the euro batch workhorse; card push payouts (sending funds to a debit card) offer speed in markets where bank rails are slow, at higher cost and with card-network rules of their own.

The orchestration logic needs four things. A routing policy that picks the rail by country, amount, seller tier and urgency, with fallback to a slower rail if the instant rail rejects. A payout state machine with states such as created, submitted, in_transit, paid, failed and returned, and with every transition posting ledger entries. Idempotent submission so a timeout never produces a second payout; derive the idempotency key from the payout row, not from the request. And a returns handler that credits the funds back to seller payable, marks the bank account as suspect, notifies the seller and blocks automatic retry until the account details change. A payout that “failed” at the PSP but “paid” at the bank is the worst case, and only reconciliation catches it.

Reconciliation: three sources of truth, one answer

Reconciliation is the discipline that makes every other part trustworthy. You have three independent records: your ledger, the PSP’s balance transactions and settlement reports, and your bank statements. Daily, you must prove that these agree. Match on PSP identifiers first (charge, transfer, payout and balance-transaction IDs), then on amount and date, and park unmatched items in an exceptions queue with an owner and an age.

The most useful single check is a balance equation: the sum of your clearing asset account should equal the PSP’s available plus pending balance, and the sum of seller payable, reserve and escrow liabilities should equal what you could be called upon to pay out. When those diverge, the delta is a bug or a loss, and its size narrows the search. Fees are the most frequent source of drift, because processor fees are often netted in settlement files and may be billed to different accounts depending on charge type. Foreign exchange adds another layer: if a payout converts currency, you must record the conversion as a pair of ledger entries with an FX gain-or-loss account, not bury it in the payout amount.

Build reconciliation as code that runs on a schedule and alerts, not as a monthly spreadsheet. Treat every exception as a ledger entry waiting to be written: a missing payout settlement becomes a reversing entry or a receivable once investigated.

The regulatory perimeter, described generally

Holding and moving other people’s money is regulated. The details depend on where you operate and how your flows are structured, and nothing here is legal advice. The structural questions are consistent, though.

In the United States, money transmission is licensed state by state, and federal registration with FinCEN as a money services business is a separate matter. Platforms commonly avoid becoming transmitters by letting a licensed PSP hold and move the funds under the PSP’s licences, with the platform instructing rather than custodying. Whether that holds depends on the facts of the flow, including whether the platform ever has control of funds and whether it is acting as an agent of the payee. In the European Union and United Kingdom, payment services and electronic money are licensed activities, and PSD2 contains an exclusion for commercial agents. According to the Clifford Chance briefing on PSD2 and online marketplaces, from 1 January 2018 the exclusion applies only where the agent acts for either the payer or the payee, not both, which made it harder for marketplaces that represent both sides to rely on it. Whether any given marketplace qualifies is a fact-specific legal question, and proposals in the PSD3 and Payment Services Regulation package, reported by multiple law firms and by Stripe’s own guidance, aim to narrow it further. Verify the current legislative status before relying on any reading.

The architectural consequences are practical. A design where the licensed PSP holds all funds and you only instruct transfers is usually easier to defend than one where funds sit in your own operating account. Keep a clean ledger separation between platform operating money and customer funds, because safeguarding obligations, where they apply, require exactly that. And make flows configurable by jurisdiction, because the hold periods, reserve rules and onboarding data differ by country.

Trade-offs, Gotchas, and What Goes Wrong

Platform-liable charge models concentrate risk. Destination charges and separate charges debit the platform balance first. That is operationally convenient and gives you control, but a bad month of fraud or a collapsing seller category lands on your balance sheet. Reserves and payout delays reduce the exposure and also reduce seller satisfaction. There is no free option.

Transfers are not self-healing. Stripe’s documentation says failed balance-to-balance transfers are not retried automatically. If your transfer worker treats a “balance insufficient” error as terminal and logs it, sellers go unpaid and support tickets arrive days later. Model transfers as a queue with explicit retry policy, backoff and an alert on age.

Instant payouts remove your safety net. The faster the rail, the less time you have to detect fraud before irrevocable settlement. A common pattern is to offer instant payout only to verified, seasoned sellers, up to a limit tied to their reserve, and to keep new sellers on a slower rail or a hold.

Rounding drift is a silent leak. If each seller’s fee is rounded independently and a refund reverses a proportional share, the pennies do not always return to zero. Define one rounding rule, and for partial refunds, compute the reversal from the original ledger lines rather than recomputing from percentages. Our code above uses banker’s rounding and largest-remainder allocation for that reason.

Holds create legal and product ambiguity. Holding a seller’s money for longer than your terms and your PSP’s rules allow can trigger complaints or regulatory questions, and a “hold” with no expiry is a standing liability. Document the conditions, notify the seller, and expire holds automatically.

Onboarding friction versus loss. Demanding full KYB up front cuts conversion; deferring it increases the number of sellers who list, collect orders and then fail verification with money already in flight. Tiering with a held payout is the compromise, but it means some sellers will churn at the verification step after earning money. Plan for forfeiture and refund rules for that case in your terms.

Anti-pattern: treating the PSP dashboard as the ledger. Teams that skip their own ledger discover, at the first audit or the first multi-seller refund dispute, that they cannot answer basic questions such as “how much do we owe sellers right now”. Retrofit is painful because history cannot be reconstructed from PSP exports alone.

Anti-pattern: using the word escrow loosely. Calling delayed payout “escrow” in marketing invites a legal characterisation you may not intend. Use precise language and have counsel review it.

Practical Recommendations

Start with the liability question. Decide in writing who absorbs a refund, a chargeback and a seller default, and pick the charge model that matches. For most branded marketplaces with one seller per order, that is destination charges; for multi-vendor carts, separate charges and transfers; for software platforms whose sellers own the customer relationship, direct charges. Then build the ledger before the integration, so that every PSP event maps to a balanced journal entry from day one.

Treat onboarding and payouts as one system. A seller’s verification tier should drive their payout schedule, their reserve percentage and their instant-payout eligibility. Make each of these a configuration keyed by tier and country, not hard-coded constants, because you will change them as you learn your loss rates.

Invest early in the unglamorous parts: idempotent workers, retryable transfers, a returns handler, and daily reconciliation. They are the difference between a platform that scales and one that needs a finance team of five to keep the books straight.

A short checklist:

  • [ ] Charge model chosen and liability for refunds, disputes and seller defaults documented.
  • [ ] Double-entry ledger with escrow, seller payable, reserve, fee revenue and payout-in-transit accounts; append-only entries with unique business keys.
  • [ ] All amounts as integer minor units with currency exponent from ISO 4217; one documented rounding rule and largest-remainder allocation.
  • [ ] Holds modelled as state machines with reason codes, owners and automatic expiry.
  • [ ] Tiered KYB with sanctions and PEP screening at onboarding, on change and on a schedule; payouts gated by tier.
  • [ ] Per-seller reserves and exposure tracking; negative-balance receivable and write-down policy.
  • [ ] Payout state machine, idempotent submission, rail fallback and returns handling per rail.
  • [ ] Daily three-way reconciliation (ledger, PSP, bank) with an exceptions queue and ageing alerts.
  • [ ] Counsel has reviewed the regulatory perimeter and the use of the word “escrow”.

This article is systems and architecture analysis only. It is not legal, regulatory, tax or investment advice.

Frequently Asked Questions

What is the difference between direct charges and destination charges?

With direct charges the payment is created on the seller’s connected account, appears in the seller’s balance, and refunds and chargebacks reduce the seller’s balance while the platform earns an application fee. With destination charges the payment is created on the platform and a portion is transferred to the seller, so refunds and chargebacks debit the platform balance first. Destination charges suit branded marketplaces; direct charges suit software platforms whose sellers own the customer relationship.

When should a marketplace use separate charges and transfers?

Use them when the simple one-buyer, one-seller shape does not fit: a cart spanning several sellers, a charge taken before the seller is known, a transfer made before funds arrive, or a payout that differs from the payment amount. The platform charges first and moves money later. The cost is complexity, because you must monitor your balance, retry failed transfers yourself, and keep ledger entries consistent across several recipients and potential partial refunds.

It depends on jurisdiction, contract terms and how the funds are held. Many platforms use delayed payout through a licensed payment provider rather than true escrow, because holding funds themselves can trigger money transmission or e-money rules. Providers also limit arbitrary holds and recommend releasing funds once recipients are identified. Treat this as a legal question: have counsel review the flow, the terms and any use of the word escrow in your product.

How do you handle negative seller balances after a chargeback?

Layer the defences. Withhold a rolling reserve per seller, delay payouts for new or risky sellers, and track exposure. When a dispute lands, debit reserve first, then seller payable, then record any shortfall as a receivable. Depending on the PSP and the account configuration, the PSP or the platform bears uncollected losses, and some providers debit the seller’s bank account automatically where supported. Write down receivables you are unlikely to recover.

What does KYB onboarding need for marketplace sellers?

At minimum: legal entity details, registration data, a representative and, where required, ultimate beneficial owners, plus a bank account in the entity’s name. Run sanctions and politically-exposed-person screening at onboarding, on changes and periodically. Tier the flow so sellers can list at low limits early while payouts stay held until verification completes. Exact requirements depend on country and your payment provider, so follow their requirement events rather than hard-coding a document list.

Why do I need my own ledger if the payment provider already has balances?

Provider balances show what the processor holds in aggregate. They do not show how much belongs to each seller, how much is your fee revenue, how much is a reserve, or what you owe for pending refunds. A double-entry ledger gives the business view, supports audit and reconciliation, and survives a change of provider. Without it you cannot reliably answer “how much do we owe sellers today” or trace a discrepancy.

Further Reading

By Riju — about

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *