Referral Programs skill for Codex
Reward real customers, not signup farms. Codex sizes referral rewards from margin and CAC before writing code, then builds attribution, a pending-to-rewarded state machine and idempotent Stripe credit grants that fire only after a paid invoice clears the refund window. Self-referrals, disposable emails and coupon-site leaks are blocked by design, and terms, affiliate disclosure and tax questions are flagged for legal and accounting review.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- referral-programs Installs to ~/.agents/skills/referral-programs/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install referral-programs The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project referral-programs Installs to .agents/skills/referral-programs/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/referral-programs.zipunzip -o referral-programs.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) referral-programs PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $referral-programs, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Designs and implements customer referral and affiliate programs for SaaS, apps and e-commerce - reward structure and economics, qualifying events, referral codes and link attribution, reward fulfilment via Stripe credits or coupons, fraud controls, terms, disclosure and payout operations - with tools such as Rewardful, FirstPromoter, PartnerStack, Tolt or a custom build. Use when asked to add a refer-a-friend feature, launch an affiliate program, decide referral rewards, stop referral abuse, or measure whether referrals are profitable.
Use it when
- You are adding a refer-a-friend or affiliate program to a product
- Reward levels need to be set from margin and acquisition cost
- An existing program is being gamed with fake or self-referrals
- You need to measure whether referred customers are profitable
Use something else when
- You are growing newsletter subscribers through reader referrals: use newsletter-growth
- You need core Stripe subscription and invoice setup first: use stripe-billing
How to check the result
In Stripe test mode, a referred account that pays and passes the refund window triggers exactly one reward per side, and a replayed webhook or self-referral grants nothing.
The mistake it prevents
Paying rewards at signup instead of after a qualifying paid event, which invites signup farms within days.
A program is done well when the reward is paid only after the referred customer has created real value, the economics hold at the expected volume, fraud is blocked by design rather than by manual review, and the terms and disclosures are clear enough that nobody is surprised.
Pick the program type
| Program | Who refers | Reward | Fits |
|---|---|---|---|
| Customer referral (refer-a-friend) | Existing users | Credits, free months, upgrades, two-sided | Products with organic word of mouth, self-serve signup |
| Affiliate | Creators, publishers, consultants | Cash commission (one-time or recurring %) | Content-driven acquisition, higher price points |
| Partner / reseller | Agencies, integrators | Revenue share, margin, co-selling | B2B with services around the product |
Customer referral and affiliate programs can coexist; keep their codes, attribution and payouts separate so one does not pay twice for the same customer.
Economics first
Write this before choosing rewards:
- Average first-year gross margin per customer (M): ...
- Current blended CAC from paid channels: ...
- Max acceptable referral cost per acquired customer: <= ~20-30% of M, and below paid CAC
- Expected referral volume per month: ...
- Reward cost at that volume (both sides): ...
- Refund / chargeback rate in the first 60 days: ...
Defaults that work for many SaaS products:
- Two-sided reward: referrer and friend each get value (e.g. one month free, or a credit worth roughly one month). Two-sided converts better than one-sided because the invite reads as a gift.
- Rewards in product value (credits, upgrades) for customer referrals; cash for affiliates.
- Affiliates: 20-30% recurring for 12 months, or a one-time bounty; 30-90 day cookie window, last-click.
- Caps: a maximum number of rewarded referrals per account per year, unless the user is a known partner.
Qualifying event
Never reward on signup alone. Reward when the referred account:
| Business | Qualifying event |
|---|---|
| SaaS subscription | First paid invoice settled AND past the refund window (e.g. 30 days) |
| Free-to-paid app | Paid conversion, or a strong activation event if rewards are tiny |
| E-commerce | Order delivered and past the return window |
| Marketplace | First completed transaction on both sides |
Implementation (custom build)
Data model:
CREATE TABLE referral_codes (
code text PRIMARY KEY, -- short, unambiguous (no 0/O, 1/l)
user_id uuid NOT NULL REFERENCES users(id),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE referrals (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
code text NOT NULL REFERENCES referral_codes(code),
referred_user_id uuid NOT NULL UNIQUE REFERENCES users(id), -- one referrer per account
status text NOT NULL CHECK (status IN ('pending','qualified','rewarded','rejected')),
reject_reason text,
qualified_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE referral_rewards (
referral_id uuid NOT NULL REFERENCES referrals(id),
recipient text NOT NULL CHECK (recipient IN ('referrer','referred')),
external_ref text, -- e.g. Stripe balance transaction id
PRIMARY KEY (referral_id, recipient) -- makes granting idempotent
);
Flow:
- Link
https://example.com/r/<code>sets a first-party cookie (30-90 days) and redirects to signup. Store the code server-side at signup; do not trust client-side state alone. - At signup, create the
referralsrow aspendingafter fraud checks (below). - On the qualifying event (a webhook such as Stripe
invoice.paid, then a delayed job after the refund window), setqualified, then grant rewards inside a transaction that inserts intoreferral_rewardsfirst; the primary key prevents double grants on webhook retries. - Notify both sides when the reward lands.
Granting a Stripe credit (Node, stripe SDK; negative amount = credit applied to future
invoices):
const txn = await stripe.customers.createBalanceTransaction(
referrerStripeCustomerId,
{ amount: -1500, currency: "usd", description: `Referral reward ${referral.id}` },
{ idempotencyKey: `referral-reward-${referral.id}-referrer` },
);
Alternative: attach a one-time coupon or promotion code to the friend’s checkout. Run Stripe calls in test mode while developing; enabling rewards against live customers moves real money and needs the user’s explicit go-ahead.
Buy instead of build when you need affiliate payouts, tax forms and partner dashboards: Rewardful, FirstPromoter, Tolt (Stripe/Paddle-centred), PartnerStack (B2B partner programs). Check which billing provider each supports before choosing.
Fraud controls
| Abuse | Control |
|---|---|
| Self-referral with a second email | Reject when payment fingerprint (Stripe card fingerprint), device, or verified domain matches the referrer |
| Disposable emails | Block known disposable domains; require email verification before pending |
| Signup farms | Reward only after paid qualification; per-account caps; velocity alerts (e.g. > 10 referrals/day) |
| Coupon-site leakage of codes | Affiliates: forbid coupon-site and brand-bidding in terms; monitor for code on coupon sites |
| Refund after reward | Qualify after the refund window; claw back credits in terms |
| Affiliate brand-keyword bidding | Prohibit in terms; check ad auction insights |
Log every rejection with a reason; review a sample monthly for false positives.
Product surface
- Share page in the app: personal link, copy button, native share on mobile, pre-written message the user can edit, live status of their referrals (pending, qualified, rewarded).
- Prompt at moments of delight (after a success, a milestone), not on day one.
- Show the friend’s landing page who invited them and what they get.
- Accessibility: copy button announces success to screen readers; status uses text, not colour alone.
Terms, disclosure and tax (not legal advice)
- Written terms: eligibility, what qualifies, reward value and timing, caps, expiry, prohibited methods (spam, paid search on brand, coupon sites), right to cancel, clawback.
- Affiliates and incentivised referrers must disclose the relationship (FTC Endorsement Guides in the US; ASA/CAP code in the UK; similar elsewhere). Put disclosure requirements in the affiliate agreement.
- Referral messages sent by your system to friends’ email addresses can count as your commercial email; prefer letting users share links themselves.
- Cash payouts to affiliates can trigger tax reporting (e.g. US W-9 and 1099 forms) and payout compliance; an accountant should confirm obligations. Have a lawyer review terms before launch.
Measuring
- Referral share of new paying customers, referral conversion rate (clicks to qualified), cost per qualified referral vs paid CAC, 6-month retention of referred vs other customers.
- Participation: share of active users who have shared at least once.
- Fraud rejection rate and false-positive appeals.
Gotchas
- Rewarding signups: farms appear within days.
- Two programs paying for the same customer (affiliate cookie plus customer code).
- Credits that never expire on the balance sheet; set expiry and account for liability.
- Webhook retries double-granting rewards without an idempotency key.
- Referral links that break attribution when the friend signs up on mobile in another browser; let the friend enter a code manually as a fallback.
Verification
- Test mode end to end: click link, sign up, pay, advance past the window (test clocks in Stripe Billing), reward granted once, replayed webhook grants nothing.
- Self-referral with the same test card is rejected with a logged reason.
- Dashboard shows cost per qualified referral next to paid CAC.
Output template
## Referral program: <product>
**Type:** customer referral | affiliate | both
**Economics:** margin, max cost per referral, expected volume, monthly cost
**Reward:** referrer ..., friend ..., cap ..., expiry ...
**Qualifying event:** ...
**Build/buy:** <tool or custom>; data model and webhook flow
**Fraud controls:** table
**Terms and disclosure:** draft + reviewer (legal/accounting)
**Launch checklist / awaiting approval:** live-mode rewards, payouts What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Referral Programs"
short_description: "Reward real customers, not signup farms"
default_prompt: "$referral-programs Add a refer-a-friend feature where both sides get a month free after the friend's first paid invoice" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.