A referral arrives pending or unpaid depending on your settings, or is rejected on the spot if it fails a check. Approving a pending referral makes it payable; rejecting it does not.
The states#
- Pending — recorded, not yet payable.
- Unpaid — approved and waiting for a payout batch.
- Paid — settled in a batch.
- Rejected — kept for the record, never payable.
These four are the only states, and the moves between them are fixed: pending can become unpaid or rejected; unpaid can become paid or rejected; paid and rejected are both dead ends — nothing moves out of either automatically. An attempt to move a referral somewhere the state machine doesn’t allow is refused rather than silently ignored, so a bug elsewhere in the plugin can’t quietly mark something paid that was never approved.
Rejected referrals are not deleted. An affiliate asking why they were not paid deserves an answer, and a deleted row cannot give one.
What decides a referral’s starting state#
Three things can hold or reject a new referral before it ever reaches “unpaid”, checked in this order of authority:
- The risk scorer says block — rejected immediately, whatever the amount. (In the free plugin the scorer never says this — see Fraud scoring, and why it fails open.)
- The risk scorer says review — held pending, whatever the amount.
- The commission is at or above your review threshold — held pending, even though the scorer approved it. A threshold of zero turns this check off entirely rather than holding everything.
Anything left over goes to “unpaid” automatically if you’ve turned on auto-approval; otherwise it’s held pending. The default is to hold everything, so a programme that has never touched these settings behaves the same way it always has.
Safeguards that ship free#
- Self-referral blocking — an affiliate cannot buy through their own link, coupon, or referring domain. One check, applied the same way regardless of which of those three routes produced the attribution.
- One commission per order — before anything else runs, the creator checks whether the order already has a referral and refuses a second one, however many times the order’s status changes afterward.
- Hold for review — commissions above a threshold you set wait for a human, ahead of auto-approval.
- Duplicate order guard — the same one-per-order check that blocks a legitimate second attribution also blocks an accidental one, if a webhook or a status transition fires twice for the same order.
Refunds#
A refund or cancellation reverses a commission automatically — but only if it hasn’t been paid yet. The reversal checks the referral’s current status first: pending and unpaid referrals are rejected outright when the order behind them is refunded or cancelled, and that’s a straight rejection, not a proportional reduction — a 30% refund on an order still rejects the whole commission rather than clawing back 30% of it. A referral that’s already been marked paid is left untouched. Reversing money that’s already left in a batch is out of scope for the free build — there’s no automatic clawback against a future payout, and no line item that appears on a later batch to recover it. If you need to recover an already-paid commission, that’s a manual adjustment you make yourself, not something the plugin does for you.
This automatic reversal is itself governed by a setting — refund clawback is on by default, on the reasoning that a refunded sale didn’t happen, so the commission on it isn’t owed. Turning it off stops the automatic reversal only; an admin manually rejecting a referral by hand always works, refund or not, and isn’t affected by this setting either way.
Auto-approval#
Auto-approving suits a programme with few affiliates you already trust. It suits a public programme much less: fraud safeguards catch the mechanical cases, not the affiliate who has quietly built a coupon-code site around your brand — and remember that in the free plugin, “fraud safeguards” means the review-threshold hold alone, since the risk scorer itself is Pro. A public programme running auto-approval on the free plugin is relying entirely on the threshold catching anything unusual; there’s no scoring underneath it to catch what a threshold misses.