Referral rewards on copy-trading subscriptions

The affiliate commission copy trading pays when a referred user subscribes to a leader — what triggers it, what the reward is a percentage of, where to configure it, and why the base figure is unreliable.

7 min readUpdated 6 August 2026affiliate, referral, mlm, commission, allocation

Copy trading pays an affiliate commission. It is easy to miss, because nothing on any copy-trading screen mentions it: the trigger lives in the subscribe endpoint, the configuration lives in the affiliate addon, and the two never refer to each other.

If you run a referral programme, this is a live cost line on every subscription.

What fires, and when

One call, from one place: the subscribe endpoint, after the subscription and all its wallet transfers have committed.

Subscribe with per-market allocations — the only route that pays a copy-trading referral reward
Condition name COPY_TRADING
Paid to The referrer of the subscribing user
Fires Once per subscription, at subscribe time
Reward base The sum of every market allocation in the request
Currency passed The literal string USD
Source id COPY_TRADING:follower:{followerId}

It fires once, when somebody subscribes. It does not fire on copied volume, on realised profit, on a top-up to an existing allocation, on adding a market to an existing subscription, or on anything the follower does afterwards. A follower who subscribes and never has a single trade copied still earns their referrer the full commission.

There is no path anywhere in the addon that pays a referrer on ongoing copy-trading activity. Design the programme around that.

The reward is recorded against the source id COPY_TRADING:follower:{followerId}, which carries a unique index, so it is deduplicated per subscription. A retried request cannot pay twice. On a BINARY or UNILEVEL structure each upline level gets its own suffixed id (…:L1, …:L2), so the same protection applies per level.

The reward base, and why it is unreliable

The endpoint sums quoteAmount + baseAmount across every allocation in the subscribe request, then passes that number to the affiliate engine with the currency literal "USD".

Nothing converts it. Nothing checks that the assets are comparable.

A follower who allocates 500 USDT on BTC/USDT gets a base of 500 — reasonable.

A follower who allocates 0.01 BTC and 200 USDT on the same market gets 0.01 + 200 = 200.01, and the ~$600 of BTC contributes one hundredth of a unit. A follower who allocates 2 ETH and nothing else gets a base of 2, and — because the shipped condition has a 50 minimum — earns their referrer nothing at all.

The rate you set is applied to that number and paid out in the condition's own rewardCurrency (USDT by default). So on a book that is genuinely multi-asset, the commission bears no stable relationship to what the follower actually committed.

This is a defect to design around, not a setting to fix. Two practical mitigations: run leaders on quote-only allocations where you can, and set the rate against the typical quote allocation size on your busiest markets rather than against an average that base-side allocations have distorted.

The threshold that is in the comment, and the one that is real

The subscribe endpoint's comment says "Minimum threshold: 50 USD equivalent total allocation". The endpoint does not implement that. Its only guard is totalAllocation > 0; any allocation at all reaches the affiliate engine.

The real minimum lives one layer down, on the condition itself. The affiliate engine compares the base against the condition's minAmount and returns without paying if it is lower. COPY_TRADING ships with minAmount = 50, so on a default install a 50-unit floor does bind — it simply is not the copy-trading code enforcing it, it is editable per condition, and it is compared against the unconverted mixed-asset number described above.

If you change or remove minAmount, nothing in copy trading will stop a one-unit allocation from earning a commission.

Where to configure it

Everything is on Admin → Affiliate → Conditions (/admin/affiliate/condition), in the mlm_referral_condition table. Two rows are relevant.

Row Ships Seeded values Fires
COPY_TRADING Enabled 3%, minAmount 50, paid in SPOT / USDT Yes — this page
COPY_TRADING_PROFIT Disabled 1%, minAmount 5 Nothing calls it

COPY_TRADING seeds with status enabled and a 3% percentage reward. It is one of fifteen conditions active out of the box.

Existing installs are untouched by upgrades — the seeder skips by name — so whatever your operator chose previously still stands. Check the row before assuming either state.

To change what you pay, edit the COPY_TRADING row:

  • reward and rewardType — a PERCENTAGE of the base, or a FIXED amount per subscription. A fixed amount sidesteps the unreliable base entirely and is worth considering for exactly that reason.
  • minAmount — the floor, compared against the base described above.
  • rewardWalletType and rewardCurrency — where the commission lands and what it is denominated in. SPOT / USDT by default.
  • status — off pays nothing and hides the rule from the members' commission rates page.
  • period — ignored. COPY_TRADING is event-driven, so the calendar window never applies to it.

name is a key, not a label. The engine looks the condition up by name and rejects any name it does not recognise, so renaming the row silently switches the commission off. Use title and description for member-facing wording.

Nothing in the platform calls processRewards with that name, so it is not event-driven — which means the hourly affiliate evaluator picks it up instead. That evaluator resolves the COPY_TRADING condition type to EXCHANGE_ORDER ledger transactions.

Enable it and you will not be paying on copy-trading profit. You will be paying a recurring percentage of your referred users' exchange order volume, stacked on top of whatever SPOT_TRADE already pays on the same fills.

Leave it off unless that is genuinely what you want.

Prerequisites, and the failure mode you will not see

Three things have to be true before a single reward is written:

  1. The mlm extension is enabled. If it is not, the engine returns immediately and nothing is recorded — no error, no log line at the copy-trading end.
  2. The COPY_TRADING condition exists with status enabled. If not, the engine logs Referral condition not found or inactive: COPY_TRADING at warn level and returns.
  3. The subscribing user has an ACTIVE referral row naming a referrer. A PENDING referral — which is what every new referral is when affiliateRequireApproval is on — earns nothing, and nothing back-pays it once it is approved.

Who is paid depends on the MLM structure. Under DIRECT it is the one referrer. Under BINARY or UNILEVEL the engine walks the sponsor chain — who invited whom, from mlmReferral.referrerId — and pays each configured level a share of the condition's reward. Tree placement and spillover do not change who gets paid.

The whole call is wrapped in try/catch with a bare console.error. A failure never blocks the subscription, never rolls it back, and never surfaces anywhere an operator looks — not on the copy-trading dashboard, not in copy_trading_audit_logs, not on the subscription row.

A subscription that paid no commission and a subscription that paid one look identical from the copy-trading side. The only place to check is Admin → Affiliate → Rewards (/admin/affiliate/reward), filtered by the COPY_TRADING condition, cross-referenced against subscriptions created in the same window on /admin/copy-trading/follower.

Do that check after any change to the affiliate configuration, and after any upgrade.

What happens once a reward exists

The row is written unclaimed. One notification actually goes out: the referrer gets "Referral Reward Earned" linking to /affiliate/reward.

An administrator notification — "MLM Reward Processed", linking to /admin/affiliate/reward — is attempted as well, but it never reaches anybody. The reward code asks for recipients by the permission name View MLM Rewards, and no such permission exists: permission names on this platform are dotted keys, and the affiliate reward ones are access.affiliate.reward, view.affiliate.reward, create.affiliate.reward, edit.affiliate.reward and delete.affiliate.reward. The lookup matches no permission row, so the fan-out resolves to zero administrators and sends nothing. You cannot grant your way onto that list — the name is not grantable, so no administrator is ever told a reward was written. Watch the Rewards screen instead.

The money is not credited at that point. The referrer claims it themselves, and the claim credits the condition's rewardWalletType wallet in its rewardCurrency, creating the wallet if they do not have one. An unclaimed reward is a liability you are carrying, not a payment you have made.

Programme design, in short

  • Pay on acquisition. This condition rewards the moment a referral commits capital, and nothing rewards them afterwards. If you want to reward retention, it will not come from here.
  • Prefer a fixed reward, or a percentage tuned to quote-only allocations. The percentage base is not a money amount on a multi-asset book.
  • Set minAmount deliberately. It is the only floor, and it is measured in that same unreliable unit.
  • Watch the reward table, not the copy-trading screens. Copy trading will never tell you the commission failed.
  • Remember the follower can leave immediately. Stopping a subscription returns their capital and does not claw the commission back. A short minimum-allocation floor plus a generous rate is an abusable combination.