Commission conditions

The rules that decide what earns a commission — the two engines that pay them, reward types and minimums, the currency trap that stops a rule paying anyone, and the overlap guard that keeps you from paying 8% when you meant 5%.

6 min readUpdated 3 August 2026conditions, commission, cron, overlap, currency

A condition is one commission rule. It says what activity pays, how much, in what currency, above what minimum, and whether it is switched on. Everything your programme costs is the sum of the conditions you leave active.

They live on Admin → Affiliate → Conditions and in the mlm_referral_condition table. Thirty-seven ship with the platform; fifteen are active on a fresh install.

What a condition is made of

Field What it does
name The trigger key. Unique, and not free text — see below.
title / description What members see on the public commission-rates page.
type The activity family. One of 16 values; drives which ledger entries the hourly evaluator scans.
reward The number. A percentage, or an absolute amount.
rewardType PERCENTAGE or FIXED.
rewardWalletType FIAT, SPOT or ECO — where the money lands at claim time.
rewardCurrency The unit the commission is denominated and paid in.
rewardChain Optional, for ECO rewards on a specific chain.
minAmount Below this, the activity does not qualify. Denominated in rewardCurrency.
status Active or not. Inactive rules pay nothing and are hidden from members.
period DAILY, WEEKLY or MONTHLY — the evaluation window for cron-driven rules.

The reward engine looks a condition up by name and refuses any name it does not recognise. Creating a condition called MY_CUSTOM_BONUS produces a row you can see on the admin screen, that shows up on the members' commission-rates page, and that will never pay anybody — no code path triggers it and the event-driven validator rejects unknown names outright.

If you need a different rate for an existing trigger, edit that condition. Use title and description for the wording your members read; leave name alone.

Two engines, and which one pays your rule

This is the single most important distinction on this page. It changes how fast a commission appears, what a percentage is a percentage of, and whether the period field means anything.

Event-driven — paid at the moment of the transaction

Nineteen conditions are triggered directly by the code that processed the activity. The commission row exists within seconds, and the percentage is applied to that one transaction's amount.

WELCOME_BONUS · ECOMMERCE_PURCHASE · ICO_CONTRIBUTION · STAKING · STAKING_LOYALTY · AI_INVESTMENT · INVESTMENT · GENERAL_INVESTMENT · FOREX_INVESTMENT · NFT_PURCHASE · NFT_SALE · P2P_TRADE · P2P_TRADE_COMPLETION · COPY_TRADING · FUTURES_TRADE · BINARY_WIN · BINARY_TRADE_VOLUME · FX_TRADE_COMMISSION · FX_TRADE_VOLUME

For these, period is ignored.

Cron-driven — paid hourly, per calendar period

Everything else is evaluated by Process MLM Referral Conditions, an hourly job visible in Admin → System → Cron under the mlm category. Each run:

  1. Loads every active condition and every ACTIVE referral.
  2. Skips the nineteen event-driven names, so no activity is ever paid twice.
  3. For each remaining condition, sums the referred user's qualifying, completed transactions inside the current calendar period — and again inside the previous one, so a transaction landing just before a period boundary is not lost.
  4. Creates at most one reward per condition, per referrer, per referred user, per period.

The percentage is applied to the summed period volume, not to a single transaction. A 3% monthly rule on a member who deposits ten times is 3% of the month's total, once.

Neither the create nor the update endpoint accepts period, so every condition sits on the model default of DAILY unless somebody changes the column directly. If you want weekly or monthly aggregation, that is a database change, and the effect is significant: DAILY means one reward per referred user per day, MONTHLY means one per month.

Reward types

PERCENTAGEreward is a percentage of the qualifying amount. Under BINARY or UNILEVEL that result is then split by your level percentages.

FIXEDreward is an absolute amount in rewardCurrency, paid once when the threshold is met. Under a multi-level structure each level receives its configured percentage of the fixed amount — so a 50 USDT fixed reward with levels of 50/30/20 pays 25 / 15 / 10, not 50 each.

Two seeded rules do something less obvious. FX_TRADE_VOLUME is stored as PERCENTAGE with a value of 100, which the Forex Trading addon reads as 1.00 per lot — not 100%. Its partner FX_TRADE_COMMISSION is a genuine percentage of the commission the trader paid. They are the two halves of one introducing-broker rebate and are meant to run together.

Minimums and the currency trap

minAmount is expressed in the condition's reward currency, and this is where most "nobody ever qualifies" reports come from.

Transactions on Bicrypto carry no currency of their own — an amount is denominated by the wallet it sits on. The hourly evaluator therefore builds a conversion table into the reward currency, converts the threshold into each wallet's currency to filter rows in SQL, and converts the resulting sums back before comparing and paying.

Three ways that goes wrong:

  • The reward currency cannot be priced. With no rate for the target currency there is no denominator, so nothing can be valued against it — including activity already in that currency. Every condition paying in it stops. The cron log says so explicitly, rate-limited to a few times a day so it does not bury the rest of the log.
  • A referred user's wallet currency cannot be priced. That volume is excluded rather than counted 1:1 — counting an unpriced token at parity is how 0.4 BTC becomes 0.40. The job logs which currencies it skipped.
  • Nobody holds a wallet yet. A referred user with no wallets has no transactions to sum. The job says so rather than reporting a clean run.

New conditions seed as SPOT / USDT, which matches how a Bicrypto install actually denominates activity. Older installs may still be on the original FIAT / USD default, which also puts the commission into a fiat wallet most members cannot withdraw from. There is a script for that:

# Report only — shows which conditions would move and the unclaimed exposure
node backend/scripts/affiliate-condition-currency.mjs

# Apply
node backend/scripts/affiliate-condition-currency.mjs --apply

It only touches rows still matching the seeded FIAT/USD default, so a rate you have deliberately set is left alone. It does not touch existing reward rows — but because the currency is read from the condition at claim time, retargeting re-denominates unclaimed rewards. The report prints that exposure before you commit.

Overlap — the reason your programme costs more than you think

Several conditions can collect on one piece of activity, and not only when they share a type. TRADE, SPOT_TRADE, COPY_TRADING and TOKEN_PURCHASE are four different types that all resolve to the same EXCHANGE_ORDER ledger entry. Leave all four active and a single spot fill pays all four.

Which ledger entries each type is evaluated against:

Condition type Transaction types
DEPOSIT DEPOSIT
TRADE, SPOT_TRADE, COPY_TRADING, TOKEN_PURCHASE EXCHANGE_ORDER
BINARY_WIN BINARY_ORDER
INVESTMENT INVESTMENT, INVESTMENT_ROI
AI_INVESTMENT AI_INVESTMENT, AI_INVESTMENT_ROI
FOREX_INVESTMENT FOREX_INVESTMENT, FOREX_INVESTMENT_ROI
FOREX_TRADING none — settled by the Forex Trading addon at trade time
ICO_CONTRIBUTION ICO_CONTRIBUTION
STAKING STAKING, STAKING_REWARD
ECOMMERCE_PURCHASE ECOMMERCE_PURCHASE
P2P_TRADE P2P_TRADE
NFT_TRADE NFT_PURCHASE, NFT_SALE
FUTURES_TRADE FUTURES_ORDER

The conditions list computes this for you. Every row carries the other active conditions that compete with it, the ledger types they share, and an effective percentage rate — what a referrer actually earns once every overlapping percentage rule has paid.

Turning on a condition that overlaps an already-active one returns a 409 naming the competitor and quoting the combined rate. Re-send with acknowledgeOverlap: true — which the admin screen does when you confirm the warning — to enable it anyway. The same guard runs when you create a condition already switched on.

Disabling is never guarded. Turning payouts off cannot cost anyone money.

Three pairs are exempt because they are not double payment:

  • NFT_PURCHASE / NFT_SALE — one trade, two different people paid (the buyer's referrer and the seller's).
  • P2P_TRADE / P2P_TRADE_COMPLETION — the same, on a P2P release.
  • FX_TRADE_COMMISSION / FX_TRADE_VOLUME — one rebate paid off two different bases.

The commission ceiling

Admin → Affiliate → Settings → Maximum Commission Rate is a real limit, not a display. Saving a PERCENTAGE condition above it is rejected with a message naming both numbers. Raise the ceiling first if you genuinely want the higher rate.

It does not apply to FIXED rewards — an absolute amount is not a rate — so a fixed reward of 10,000 saves happily under a 30% ceiling. Watch those by hand.

What members can see

The public commission-rates page (/affiliate/condition) lists active conditions only, and filters out any rule belonging to an addon you do not have enabled. Someone without the NFT addon never sees NFT commissions advertised. Rules backed by core features — deposits, spot and binary trading, investments — are always shown.

What you cannot do

  • Delete a condition. There is no delete endpoint, and the affiliate family has no delete. key for conditions. Disable it instead; the row stays as a record of what your programme once paid.
  • Set minAmount when creating. The create endpoint ignores it, so a new condition starts at 0 — every qualifying transaction, however small, pays. Save it, then edit it to set the minimum.
  • Rename name. The update endpoint's allow-list does not include it.

Next: Rewards and payouts — what happens between a commission being earned and money reaching a wallet.