Financial software
Multi-level referral commissions: getting the money right
Paying several levels of referrers looks like a tree walk with a percentage. The tree is the easy part. The work is making every amount traceable, safe to run twice and correct after a refund.
By itmarkerz Technologies. Updated 30 October 2026.
Where this comes from
We built a buy and sell platform on Laravel and Next.js with multi-level referral commissions and payouts, alongside live rates with a configurable margin, customer accounts and staff roles. This article covers only the technology. The code here is written for this article, and the percentages are invented.
Four things to keep separate
| Record | Holds | Rule |
|---|---|---|
| Referral link | Who referred whom, and when | Set once. Changes are rare, deliberate and logged |
| Plan | Rates per level, effective dates | Never edit a live plan; add a new version |
| Qualifying event | The sale or transaction, and its amount | Unique per source transaction |
| Ledger entries | Who earned what, from which event, under which plan | Append only; a correction is a new entry |
Keep the balance as the sum of ledger entries. A balance column that gets incremented can drift, and when it does you can’t tell which entry was wrong. If you need one for speed, treat it as a cache that you can rebuild and check every night.
Calculating, safely
DB::transaction(function () use ($event) {
$plan = Plan::activeOn($event->occurred_at);
$ancestor = $event->user->referrer;
foreach ($plan->levels as $level) {
if (! $ancestor) {
break;
}
// Unique on (event_id, payee_id, level): running twice is harmless
LedgerEntry::firstOrCreate(
['event_id' => $event->id, 'payee_id' => $ancestor->id, 'level' => $level->number],
['amount_minor' => $level->commissionOn($event->amount_minor),
'plan_id' => $plan->id, 'status' => 'pending'],
);
$ancestor = $ancestor->referrer;
}
});The details that cause most of the trouble:
- Use whole minor units or exact decimals. Never floats. Agree a rounding rule, and decide where a leftover fraction goes, so that the total paid out always adds up.
- Enforce uniqueness in the database. Jobs retry, and webhooks repeat. A unique index on event, payee and level makes a double payment impossible at the point where it counts.
- Stop the walk at a set depth, taken from the plan, and guard against loops. Validate when a referral link is created that a person can’t end up in their own ancestry.
- Handle closed accounts. If a referrer in the chain is suspended, does their share pass upwards or go unpaid? Decide this, then test it.
- Snapshot the plan. Store which plan applied on the entry, so that a later change doesn’t alter the past.
Refunds and reversals
If the original transaction fails or gets reversed, the commissions earned on it have to be undone. Keep entries pending until the source transaction has settled, so most reversals are just a cancelled pending entry. For entries already paid, post a negative one linked to the original and let it reduce the next payout. If somebody’s balance goes negative, you need a policy, since you may not be able to recover it. Run this path in testing as thoroughly as the happy one, because it is the path that loses money.
Payouts
- Set a minimum payout, a schedule and an approval step for staff, with separate roles for approving and paying.
- Lock the entries included in a payout batch, so nothing is paid twice while a batch is running.
- Treat a failed payout as a state to resolve, and return its entries to the available balance only after you know that the money didn’t go.
- Give each user a statement listing every entry with its source, level and plan, while protecting the privacy of the people below them. It reduces disputes more than anything else on this list.
- Tax or service charges may apply by location, as they did on this platform, so keep those as their own configurable lines.
Check it daily
Schedule a check that compares total commissions with the sum the plans should have produced from the day’s events, and alerts someone when they differ. Then watch for abuse, such as self-referrals, clusters of linked accounts or transactions that exist only to generate commission. If your commissions run through a hierarchy of brokers rather than referrals, the record-keeping is very similar, as we explain in commission logic for insurance brokers.
The platform this comes from
Buy/sell crypto platform on Laravel and Next.js: live rates with a configurable margin, customer accounts and transaction history, referral commissions, staff roles, and a Telegram bot for rates, portfolio and transaction notifications.
- Sector
- Fintech & crypto
- Year
- 2024–2025
- Stack
- Laravel, Next.js
- Engagement
- Web platform and Telegram bot
Questions
Are multi-level referral schemes legal?
That depends on the scheme, the product and where it runs, and some structures are restricted. This article covers the code and not that question, so take legal advice before you build, particularly if you pay on recruitment rather than on real sales.
Should commission be calculated when the sale happens, or later in a batch?
Record the event at the moment of the sale, and calculate from it either straight away or in a job. Keeping the event separate lets you recalculate safely and work out what happened if a rule was wrong. Hold anything that is awaiting a settlement period.
More on regulated sectors
- Commission logic and reports for insurance brokersHierarchies, renewals and reversals, from a platform we ran from about 2014 to 2019.
Does your platform pay people out of transactions?
Tell us your levels, your rules and what happens on a refund. We will tell you how we would model it.
We reply within one business day (IST).