A customer clicks your affiliate's referral link on Monday. On Wednesday they come back through your Instagram bio, grab the 10% popup code, and check out. Now one of two bad things happens: the affiliate loses their commission to last-touch attribution, or you pay commission and a discount on an order that needed only one incentive.
Every merchant running an affiliate program (GoAffPro, UpPromote, ReferralCandy…) alongside discount codes hits this. The question comes up constantly in the Shopify Community: can I block discount codes for customers who arrived through an affiliate link?
Short answer: no native setting exists. But there's a working architecture — and a newer piece of the Discount Function API makes the checkout experience much cleaner than it used to be.
(Full bilingual writeup with architecture details: canonical post on the ClawMama blog. We build open-source Shopify agent skills — github.com/clawmama-run/shopify-growth-operator-agent — and a ready-to-use Shopify Agent if you want the monitoring part without the setup.)
Why Shopify can't do this natively
Discount eligibility is conditioned on customer segments, products, collections, order minimums, combination rules. It never sees how the customer arrived. The referral source lives in your affiliate app's tracking script and cookie. Discount codes are validated at checkout entry — and checkout has no idea the customer clicked a referral link three days ago. No plan has an eligibility rule that reads "came from affiliate X."
So the fix must bridge two systems: get referral state into the cart, then let checkout logic act on it.
Fixes that look right but backfire
0% commission when a code is used. The most common affiliate-app setting people reach for. It solves double-payment by transferring the cost to your affiliate. First time a partner notices they drove a sale and earned nothing, they stop promoting you.
Cart Validation Function. You can block the order — but the customer sees a generic error, not "this code doesn't apply to you." Reads as "the store is broken."
Zeroing the discount via an automatic-discount Function. The code gets accepted and the total doesn't move. The store took their code and gave nothing. Arguably the worst ending.
Root problem in all three: the customer is never told, clearly, that the code can't be used on referral orders — and the affiliate's credit is an afterthought.
The working architecture
1. Capture referral state as a cart attribute. Cart attributes travel with the cart into checkout, and Discount Functions can read them. A small theme script detects the affiliate's referral signal (URL param or the app's cookie) and writes it via the Ajax API: POST /cart/update.js with attributes: { referral_source: "affiliate" }.
2. Attach a Discount Function to an automatic discount. Code discounts are validated before Functions get a say. So your Function runs on an automatic discount you create yourself (discountAutomaticAppCreate) — it doesn't need to discount anything; its job is to give your Function a seat at checkout. The input query reads your cart attribute plus enteredDiscountCodes.
3. Reject with enteredDiscountCodesReject. If referral state is present and the customer entered one of your marketing codes, return:
{
"enteredDiscountCodesReject": {
"codes": [{ "code": "WELCOME10" }],
"message": "WELCOME10 can't be combined with a referral order — your referral already gives you the best deal."
}
}
The customer sees a specific, human explanation. The affiliate keeps their commission because referral tracking was never touched. Nobody gets double-paid.
Three constraints from Shopify's docs:
- Only Functions backed by an automatic discount can reject codes.
- You can only reject codes still rejectable — entered but not yet applied. Act on
enteredDiscountCodesat entry time, not retroactively. - The rejection message displays in checkout and should be localized.
enteredDiscountCodesReject arrived with the 2026-01 API version — which is why older threads about this problem end with "you can't do it cleanly." You can now.
The cookie-window trap
Affiliate referral cookies persist for days or weeks. If your theme script writes the referral attribute and it lingers, a customer who clicked a partner's link three weeks ago gets their birthday-email code rejected with no idea why.
Decide deliberately: session-scoped (reject only when the referral was detected this session — fewer angry customers, some attribution leakage) or window-scoped (reject for the full cookie window — cleaner economics, but you must communicate the rule). Whichever you pick, tell your affiliates upfront.
Test before you ship
- Shop Pay / accelerated checkouts — does the rejection message surface?
- Automatic discounts + codes combination rules.
- Happy path — non-referral customers must still use the code normally.
- POS and draft orders if you use them — Function behavior differs by surface.
Where an agent fits
The rejection logic is a one-time build. The ongoing work is monitoring: catching orders where a code and a referral both fired, spotting new conflict patterns (new partner, new code campaign), flagging anomalies before they become a month-end commission dispute. That's a loop a store-operations agent can own — surfacing conflicts with evidence while the rule itself stays a decision you make once.
Verified against Shopify's Discount Function documentation as of July 2026. enteredDiscountCodesReject requires API version 2026-01+.
Top comments (0)