WebProCMS ships with a built-in affiliate program: give partners shareable referral links and coupon codes, track the clicks, signups, and sales they drive, and pay one-time or recurring commissions with payout reports. It's an opt-in premium feature — everything lives under Dashboard → Affiliates once enabled, and the public site gains exactly one route (/go/{code}) plus an invisible link-parameter listener.
Enabling
Toggle Affiliate Program on at Dashboard → Settings → Features (admin only, members-only feature). The toggle runs the module's migrations on the spot — no console access needed. Turning it off later hides the dashboard pages and 404s the public routes but keeps all data; nothing is deleted.
Commissions come from several sources, each tied to another feature: shop orders (E-Commerce), member signups and recurring membership payments (Memberships), course purchases (Courses), and event ticket sales (Event Ticketing). The affiliate module works with whichever of those are enabled — an install with only Memberships can still pay signup bounties and membership commissions.
Creating affiliates
Dashboard → Affiliates → New Affiliate. An affiliate is a name + optional email + a unique referral code (auto-generated from the name if left blank, e.g. sarah-miller). Each affiliate's edit page shows their stats (clicks, referrals, pending / owed / paid-to-date), their two shareable links with copy buttons, per-affiliate commission overrides, and their recent conversions.
Affiliates have three statuses: Active (links attribute, commissions accrue), Paused (links stop attributing new visits and conversions stop crediting; history kept), and Archived.
The two link forms
Every affiliate gets two interchangeable links:
?ref=CODEon any URL — append the referral parameter to any page on the site (https://example.com/pricing?ref=sarah). A site-wide middleware captures it on every GET request, so deep links to blog posts, product pages, or landing pages all attribute. The parameter name (refby default) is configurable in settings./go/CODE— the pretty redirect link (https://example.com/go/sarah). It 302-redirects to the homepage, sets the same attribution cookie, and (when the Analytics tie-in is on) appends UTM tags to the destination.
Both forms record a click row (landing path + external referrer domain) and set the attribution cookie. Unknown or paused codes redirect/render normally without attributing — a dead link never breaks the page.
Attribution: cookie window, first/last click, coupon codes
- Cookie window — the referral cookie (
wpc_aff) lasts 30 days by default (configurable). A visitor who clicks an affiliate link and buys three weeks later still credits the affiliate. - Attribution model — Last click wins (default): a newer affiliate link overwrites the cookie. Or First click wins: the original referrer keeps the credit for the cookie's lifetime. Either way every click is counted for the clicking affiliate's stats.
- Coupon-code attribution beats the cookie. Each affiliate can be assigned a shop coupon code (e.g.
SARAH10, matched case-insensitively against the promo code used at checkout). When an order used an affiliate's coupon, that affiliate gets the commission even if the visitor arrived through someone else's link — an explicit code names its owner. Podcast and print promotions work with no link at all. - Webhook-safe. Order attribution is bridged from the browser to Stripe's webhook context at checkout start, so commissions record correctly even though the webhook request carries no visitor cookies. Attribution never breaks checkout — every hook is wrapped so a failure in the affiliate path can't block an order.
Commission types
Conversion types, each with its own program-wide rule at Dashboard → Affiliates → Settings:
| Conversion | Default | Base amount |
|---|---|---|
| Shop order | 10% | Order subtotal after discounts — tax and shipping never earn commission |
| Member signup bounty | $0 (off) | Flat amount per referred member registration |
| Membership payment | 20% | Every paid membership invoice (first and renewals), per the duration rule |
| Course purchase | shop-order rate | The amount paid for the course |
| Event tickets | shop-order rate | The amount actually paid, net of any promo discount — free tickets earn nothing |
Course and ticket sales use the shop-order rate, since they are the same kind of one-off product sale. Their attribution is carried across the Stripe checkout by the session rather than the cookie, so a sale still credits the right partner when the purchase is finalized by the Stripe webhook (where no browser cookie exists).
Donations deliberately earn no commission: paying a cut of a charitable gift is a problem in most jurisdictions, and peer-to-peer fundraiser pages already provide proper credit for referred giving.
Shop subscription orders (recurring products) earn at the shop-order rate: the first charge earns like any order, and each renewal invoice keeps earning per the same recurring-commission duration rule memberships use (below). Attribution rides the referral cookie present when the buyer opened the subscribe page.
Percent rules take a percentage of the base amount. Flat rules are entered in major currency units — a flat value of 5 means $5.00 per conversion. $0 invoices (trials, 100%-off coupons) earn nothing.
Per-affiliate overrides: each affiliate's edit page has a Commission Overrides card — order rate, signup bounty, membership rate, and membership duration can each be overridden per partner; blank fields fall through to the program settings. This is how you give a top partner 20% while everyone else earns 10%.
Recurring commissions: duration modes
Repeat payments — membership invoices and shop-subscription renewal orders alike — earn per the recurring commission duration setting:
- Only the first payment (
once) — one commission per referred member / subscription, ever. - For a number of months (default, 12) — every payment inside the N-month window earns; after it closes, payments stop crediting.
- Lifetime — every payment for as long as they keep paying.
For memberships the window anchors on the referral date (when the referred member registered); for shop subscriptions it anchors on the subscription's first commission. The rule is evaluated at payment time from current settings.
The commission ledger: hold window and auto-approval
Every commission is a row on Dashboard → Affiliates → Conversions with a lifecycle:
- Pending — newly recorded. Commissions sit pending for the hold period (default 30 days — set it to match your refund window;
0approves instantly). - Approved — the hold has elapsed. An hourly background task auto-approves due conversions; admins can also approve early with one click. Approved = owed.
- Paid — settled by a payout (below).
- Void — a fully refunded order automatically takes its commission back, as long as it hasn't been paid yet. Already-paid commissions stay on the ledger (settle manually against the next payout). Admins can void any pending/approved conversion by hand.
Recording is idempotent — Stripe webhook retries and double-fired hooks can't create duplicate commissions.
Payouts and CSV exports
Dashboard → Affiliates → Payouts shows what each affiliate is currently owed (their approved conversions). Record payout settles the full owed balance in one step: it creates a payout row (method: manual / PayPal / account credit / Stripe, plus a reference and notes) and marks every approved conversion paid. Payout history lists every settlement with its conversion count.
Automated Stripe payouts (optional). With Send payouts via Stripe enabled in settings (requires Stripe Connect on the platform account; uses the same Stripe keys as the shop), each affiliate's edit page gains a Set up Stripe payouts onboarding flow — one click creates a Stripe Express account and walks them through Stripe's own identity/bank setup. Once their account shows Payouts enabled, the Record-payout modal offers Send via Stripe: the owed amount is transferred to their account in the same transaction that marks the conversions paid, with the transfer id stored as the payout reference. A failed transfer marks nothing paid, and retries can't double-send (the transfer is idempotent on the exact conversion set being settled). Transfers draw from the platform's available Stripe balance.
Two CSV exports for accounting:
- Balances (Payouts page) — one row per affiliate: pending, owed, paid-to-date, payout method and reference.
- Conversions (Conversions page) — the raw ledger, filterable by status and date range.
Analytics tie-in
When Tag /go link visits for Analytics is on (default), the /go/{code} redirect appends utm_source={code}&utm_medium=affiliate to the destination URL. The built-in Analytics feature already segments by UTM parameters, so affiliate traffic shows up in campaign reports with zero extra wiring — filter by utm_medium=affiliate to see all affiliate-driven sessions, or by utm_source to compare individual partners.
Settings reference
All knobs live at Dashboard → Affiliates → Settings (admin only):
- Cookie duration (days) — how long the referral cookie lasts (default 30)
- Attribution model — last click wins (default) or first click wins
- Link parameter — the query parameter carrying the code (default
ref) - Hold period (days) — days a commission stays pending before auto-approval (default 30)
- Tag /go link visits for Analytics — UTM tagging toggle (default on)
- Shop orders — percent or flat + value (default 10%)
- Signup bounty — flat amount per referred member signup (default 0 = off)
- Memberships — percent or flat + value (default 20%), plus the recurring commission duration mode and months
- Performance bonus — conversions-per-month threshold + flat bonus amount (default 0 = off)
- Self-serve applications — public application form toggle + owner notification email (default off)
- Promo assets — copy templates for the affiliate toolkit (
{link}/{code}placeholders); banner images come from the "Affiliate Assets" media category - Send payouts via Stripe — Stripe Connect automated payouts toggle (default off)
Self-serve applications
Turn on Let people apply to the program and the site gains a public application form at /affiliates/apply (name, email, website, "how will you promote us?"). Applications land as pending affiliates in a queue at the top of the Affiliates page — pending codes never track or credit anything. Approving activates the code and automatically emails the affiliate their referral link; rejecting keeps the application on record. A signed-in member who applies gets their account linked automatically, so the portal toolkit appears the moment they're approved. The form is rate-limited and honeypot-protected, and an optional owner email gets pinged on each new application.
The affiliate toolkit (member portal)
An affiliate linked to a member account sees a full toolkit on their member dashboard:
- Stats — clicks (30-day and total), conversions, pending/owed/paid balances, recent conversions.
- Share links — the
/go/{code}short link and query-param form, one-click copy. - Deep link builder — paste any page URL or path and get it back with their referral code attached; any page can be a landing page.
- Promo assets — banner images the admin uploaded to the Affiliate Assets media category (with download links), plus ready-to-paste copy templates with the affiliate's own link and code already substituted.
- Tax form (W-9) — upload a completed W-9 (PDF or image, private storage). Managers see the status on the affiliate's edit page and download it from there; files never get a public URL.
Performance bonuses
When the bonus is configured (threshold + amount), any affiliate whose real conversions in a calendar month reach the threshold automatically earns a one-time flat bonus for that month. Bonuses are approved instantly (their underlying conversions already served the hold window), show up in the ledger as "Performance bonus", and are idempotent — the hourly sweep can run any number of times without double-awarding.
Year-end report
Payouts → Year-end report exports the 1099-prep sheet: what each affiliate was actually paid during a calendar year (by payout date), their payout method and reference, and whether a tax form is on file. Affiliates with nothing paid that year are omitted. Any year is available via ?type=year-end&year=YYYY on the export URL.
What it's not
- Not multi-level. One affiliate earns per conversion; there are no sub-affiliate trees or override tiers.
- Not an automatic money mover by default. Out of the box, payouts are recorded, not executed — pay by PayPal, check, or bank transfer and log it. Opt into Stripe Connect payouts (above) to actually send the money.
- Not click fraud protection. Clicks are counted plainly; commissions only exist when real orders, signups, or invoices happen — which is where the money is, and those are all verified server-side.