Why the batch job always rots
The reconciliation-job approach starts innocently: record who's owed what, run payouts weekly. Then reality arrives — a refund lands after the payout ran, a seller changes their address mid-cycle, the job crashes halfway and half the sellers got paid, the finance sheet and the database disagree by $3.17 and nobody knows why. The core defect is architectural: the money and the obligation are tracked in different systems, and every day between sale and settlement is a day they can drift apart.
Revenue splits collapse that gap to zero. The share declaration travels with the payment, and the fan-out happens in the same settlement that credits the money — there is no window where the obligation exists but hasn't been booked.
Declaring shares
A splits array on any white-label payment, in basis points (1 bps = 0.01%), summing to exactly 10000:
{
"currency": "USDT_TRC20",
"amount": "500.00",
"splits": [
{ "bps": 8500, "recipient_merchant_id": "…seller…" },
{ "bps": 1000, "recipient_merchant_id": "…referrer…" },
{ "bps": 500, "recipient_address": "TXm4…" }
]
}Two recipient types, mixable in one declaration:
- Platform accounts (
recipient_merchant_id) — the share lands as instant, zero-fee ledger credit the moment the payment confirms, exactly like an internal transfer. This is the right shape for sellers and affiliates who transact with you repeatedly. - External addresses (
recipient_address) — the share becomes an automatic on-chain payout in the payment coin. Right for parties outside your loop: a licensor, your own treasury, a one-off rev-share.
Validation is all-or-nothing at creation: bad bps sums, more than 10 recipients, malformed or burn addresses, unknown merchants — each rejects the whole payment before a buyer ever sees an invoice. There is no partially-valid split in the system, which means there's no partially-valid split to reconcile later.
The dust problem, done honestly
Split 100.00 three ways at 3333/3333/3334 bps and floating-point math will eventually lose or invent a base unit — the classic penny-shaving bug, except on chains where the base unit is a satoshi. The fan-out therefore runs in integer base units end to end, and the final recipient absorbs the sub-unit remainder. Every settlement reconciles to the deposit exactly, by construction. It's a small design decision that eliminates an entire genre of month-end mystery.
Fees, and what this replaces
The platform fee applies once, to the deposit — platform-account shares add nothing on top, and external shares carry only their own network fee. Compare the alternatives: an on-chain splitter pays gas per recipient per payment and locks you to one chain's tooling; the manual approach pays a payout fee per seller per cycle plus the engineering cost of the batch job. Declared splits give you contract-like enforcement — the routing can't be quietly edited after checkout, because it's immutable once the payment exists — without deploying anything or leaving any chain out.
One boundary worth knowing
Splits distribute the deposit coin; Auto Settle converts it. One payment can do one or the other, not both — a split's recipients get the coin the buyer paid, and any of them can convert their own credit afterwards. In practice marketplaces overwhelmingly run stablecoin invoices with splits, which sidesteps the question entirely: everyone's share arrives already denominated in the thing they wanted.
If your take-rate currently lives in a spreadsheet and a cron job, this is the migration: put it in the payment. The ledger enforces what the batch job could only attempt.