Referral System
Affiliate and referral program guide
Referral System
Chameleon includes a built-in referral (affiliate) system that rewards users for bringing in new customers.
Overview
The referral system allows users to:
- ✅ Get a unique invite code (auto-generated)
- ✅ Share invite links with friends
- ✅ Earn commission when referrals purchase
- ✅ Track referral performance
- ✅ Convert commissions to credits
How It Works
1. Every User Gets an Invite Code
When a user signs up, the system automatically generates a unique 6-8 character invite code.
// Example codes
Code: "a7Bx9Q"
Code: "Km3pL8zR"
Code: "Qw5Ty2"
Features:
- Auto-generated on account creation
- Guaranteed unique (collision detection)
- Cannot be manually changed (system-managed)
- View at
/my-invites
2. Share Invite Link
Users can share their personalized link:
https://your-domain.com/i/a7Bx9Q
When a new user clicks this link:
- Invite code is stored in session
- New user can sign up normally
- System tracks the referrer
3. Earn Commission
When a referred user makes a purchase:
- Order is placed by the referred user
- Commission is calculated based on order amount
- Affiliate record is created linking referrer to order
- Commission status starts as "pending"
4. Commission Approval
Commissions go through a lifecycle:
| Status | Description |
|---|---|
pending | Order paid, awaiting approval |
approved | Admin approved, ready for payout |
paid | Commission paid to affiliate |
rejected | Admin rejected (refund, fraud, etc.) |
5. Convert to Credits
Once approved, commissions can be converted to credits automatically or manually.
Invite Code System
Auto-Generation
File: src/services/user.ts
async function generateUniqueInviteCode(): Promise<string> {
let inviteCode: string;
let attempts = 0;
do {
// Generate 6-8 character code
const length = 6 + Math.floor(Math.random() * 3);
inviteCode = getNonceStr(length);
// Check uniqueness
const existing = await findUserByInviteCode(inviteCode);
if (!existing) return inviteCode;
attempts++;
} while (attempts < 10);
// Fallback: timestamp-based
return `INV${Date.now().toString(36).toUpperCase()}`;
}
View Invite Code
Users can view their invite code at /my-invites:
- Click on the invite code display
- Modal shows the code
- One-click copy to clipboard
- Note: "Invite codes are automatically generated and cannot be changed"
Invite Link Format
https://your-domain.com/i/{invite_code}
When visited:
- Stores invite code in cookie/session
- Redirects to homepage
- Code is associated on signup
Commission Structure
Commission Rates
Default commission rates (can be customized):
// Example commission rates
Starter Plan: 10% commission
Professional Plan: 15% commission
Enterprise Plan: 20% commission
Commission Calculation
const commissionRate = 10; // 10%
const orderAmount = 19900; // $199.00 in cents
const commission = Math.floor(
(orderAmount * commissionRate) / 100
);
// Commission: 1990 cents = $19.90
Commission Limits
You can set:
- Minimum commission: $5
- Maximum commission: $500
- Cap per user: $10,000/month
Referral Dashboard
Users access their referral dashboard at /my-invites.
Dashboard Features
-
Summary Statistics
- Total referrals
- Total commission earned
- Pending commissions
- Conversion rate
-
Referral List
- Referred user email (masked)
- Purchase date
- Order amount
- Commission amount
- Commission status
-
Invite Tools
- Copy invite link
- View invite code
- Share on social media (Discord, etc.)
Affiliate Management (Admin)
Admins can manage the affiliate program:
Approve Commissions
-- Find pending commissions
SELECT * FROM affiliates
WHERE status = 'pending'
ORDER BY created_at DESC;
-- Approve commission
UPDATE affiliates
SET status = 'approved'
WHERE id = 123;
Set Commission Rates
Edit commission rates in the code:
// src/services/affiliate.ts
const getCommissionRate = (orderAmount: number): number => {
if (orderAmount >= 50000) return 20; // 20% for $500+
if (orderAmount >= 10000) return 15; // 15% for $100+
return 10; // 10% default
};
Fraud Detection
Monitor for suspicious activity:
- Same IP addresses
- Rapid signups from same referrer
- Chargeback orders
- Unusual purchase patterns
Implementation Details
Tracking Referrals
File: src/app/[locale]/(default)/i/[code]/page.tsx
When user visits invite link:
export default async function InvitePage({ params }: { params: { code: string } }) {
const { code } = params;
// Store invite code in cookie/session
cookies().set("invite_code", code, {
maxAge: 30 * 24 * 60 * 60, // 30 days
});
redirect("/");
}
On User Signup
File: src/auth/handler.ts
// Check for invite code
const inviteCode = cookies().get("invite_code");
if (inviteCode) {
const referrer = await findUserByInviteCode(inviteCode.value);
if (referrer) {
newUser.invited_by = referrer.uuid;
}
}
On Payment Success
File: src/services/stripe.ts
// Create affiliate record
if (user.invited_by) {
await createAffiliate({
user_uuid: user.invited_by, // Referrer
order_uuid: order.uuid,
customer_email: order.paid_email,
order_amount: order.amount,
commission_rate: 10,
commission_amount: Math.floor(order.amount * 0.1),
status: "pending",
});
}
API Endpoints
Get User Invites
GET /api/get-user-invites
// Returns user's invite code and referral stats
Update Invite Settings
POST /api/update-invite
// Body
{
"is_affiliate": true // Enable/disable affiliate status
}
Customization
Change Commission Rates
Edit src/models/affiliate.ts or src/services/affiliate.ts:
// Set custom rates
const commissionRate = 15; // 15% for all orders
// Or tiered rates
const getTieredRate = (amount: number) => {
if (amount >= 100000) return 25; // 25% for $1000+
if (amount >= 50000) return 20; // 20% for $500+
if (amount >= 10000) return 15; // 15% for $100+
return 10; // 10% default
};
Auto-Approve Commissions
By default, commissions are pending. To auto-approve:
// In src/services/stripe.ts - handleCheckoutSession
await createAffiliate({
// ...
status: "approved", // Change from "pending" to "approved"
});
Minimum Purchase Requirement
Only count referrals above a threshold:
const MINIMUM_ORDER_AMOUNT = 1000; // $10 minimum
if (order.amount >= MINIMUM_ORDER_AMOUNT) {
// Create affiliate record
}
Analytics
Referral Performance
-- Top referrers by commission
SELECT
user_uuid,
COUNT(*) as referral_count,
SUM(commission_amount) as total_earned,
SUM(order_amount) as total_revenue
FROM affiliates
WHERE status IN ('approved', 'paid')
GROUP BY user_uuid
ORDER BY total_earned DESC
LIMIT 10;
Conversion Metrics
-- Referral conversion rate
SELECT
COUNT(DISTINCT invited_by) as referrers,
COUNT(*) as total_referrals,
COUNT(CASE WHEN id IN (
SELECT DISTINCT user_uuid FROM orders WHERE status = 'paid'
) THEN 1 END) as paid_referrals
FROM users
WHERE invited_by IS NOT NULL;
Preventing Abuse
Safeguards
- Email verification - Prevent fake signups
- IP tracking - Detect multiple accounts from same IP
- Payment verification - Only count paid orders
- Manual approval - Admin reviews before payout
- Fraud detection - Monitor unusual patterns
Blocking Users
-- Revoke affiliate status
UPDATE users
SET is_affiliate = false
WHERE uuid = 'abusive-user-uuid';
-- Reject pending commissions
UPDATE affiliates
SET status = 'rejected'
WHERE user_uuid = 'abusive-user-uuid'
AND status = 'pending';
Payout Management
Commission Payout
Commissions can be paid via:
- Credits - Convert to platform credits
- PayPal - External payout
- Bank transfer - For high earners
- Platform balance - Use for future purchases
Implementation:
// Convert commission to credits
const commission = await getApprovedCommission(affiliate_id);
await increaseCredits({
user_uuid: commission.user_uuid,
trans_type: CreditsTransType.SystemAdd,
credits: commission.commission_amount / 100, // Convert cents to credits
expired_at: getOneYearLaterTimestr(),
});
// Mark as paid
await updateAffiliateStatus(affiliate_id, "paid");
Next Steps
- Credit System - How credits work
- Payment System - Purchase flow
- User APIs - Referral APIs
- Admin Guide - Manage affiliates