Guide chapters
Payments
The problem#
A marketplace payment is one buyer transaction that has to split across several recipients, survive a refund and reconcile a month later. It is also the one area where a mistake is visible immediately and costs money.
The split of responsibility#
This boundary is the most important thing in the chapter, and it is worth writing down before any code exists.
| Area | Provider | Platform |
|---|---|---|
| Taking and authorising funds | all of it | none |
| Verifying seller identity | all of it | keeps a reference and reads the status |
| Splitting the amount across sellers | executes the transfer | decides how much to whom and why |
| What an event means for the order | none | all of it |
| Refund | executes it | the effect on commission, payout and order state |
| Reconciling with the statement | source data | comparison with its own record |
Minimum version#
- One buyer payment, with the split across sellers recorded at the moment funds are captured.
- The split exists as its own record, even when it has one element.
- Payment state distinguishes authorisation, capture, partial refund and full refund.
- Every provider event lands in a ledger keyed by the provider own identifier.
A split recorded at capture time is the same pattern as the checkout snapshot, applied to money. Without it, a commission rate change recalculates something that has already happened.
What not to build yet#
- An abstraction over payment providers before the second provider.
- Your own fraud system.
- Automatic dispute resolution.
- Instant payouts. That is its own chapter with its own triggers.
Plan ahead#
A provider event is not a business event#
Being told that funds were captured does not say the order is paid, nor that a payout can go out. The platform needs its own state and its own reading, because the provider knows nothing about your commissions, refunds or hold periods.
Notifications arrive repeatedly and out of order#
An event ledger keyed by the provider identifier does three things at once: it filters repeats, it lets you reconstruct the order, and it answers whether an event arrived at all. Without it, the first repeated refund notification subtracts the amount twice.
A refund touches four things at once#
A refund changes order state, the amount payable, the commission charged and, if the money has already gone out, it requires reversing a transfer. The model has to know how much of a given payment was refunded, not merely that a refund happened.
Triggers#
- the first partial refund;
- the first provider notification that arrived twice;
- the first discrepancy between your record and the statement;
- a seller asks why the amount differs from what they expected;
- a second payment method with a different flow appears, for example deferred payment.
Next stage#
After the second trigger: an event ledger, if there is not one already. After the third: a simple discrepancy report to review by hand, before you build automatic reconciliation. After the fifth: only then a provider abstraction layer, because only then do you know what to abstract.
Common mistakes#
| Assumption | Why it costs |
|---|---|
| "Capturing funds means the order is paid." | The order may not exist, and the state has to be reconstructed by hand. |
| "Commission can be calculated at payout." | A rate change recalculates settlements from before it. |
| "A refund is a flag." | Partial refunds and a second refund in a row have no representation. |
| "A notification arrives once." | A repeat subtracts the amount twice. |
| "We will reconcile at month end." | A discrepancy from three weeks ago cannot be reconstructed. |
What works in practice#
On payments, the most important decision was treating provider events as information to interpret rather than instructions to execute. Every incoming event lands in a ledger first, and only then does the platform decide what it means for the order, the commission and the payout. That single intermediate step removed a whole class of problems with repeats and ordering.
The second thing that turned out impossible to skip is keeping captured and refunded amounts as running totals on each part of a payment. Partial refunds appear sooner than you expect, and a boolean cannot describe them.
Checklist#
- The boundary of responsibility between provider and platform is written down.
- The amount split is recorded when funds are captured.
- Captured and refunded amounts are numbers, not flags.
- Every provider event has a ledger entry keyed by its identifier.
- There is a way to compare your own record with the provider data.
- The platform has its own payment state, independent of the provider status.
I design multi-vendor platforms with onboarding, payments, moderation, and operational workflows.
Explore marketplace development