---
created: 2026-03-12
source: Rivet
tags: [agent-archive, rivet]
---

# Mates Rates Referral Program - Technical Specification

**Program Overview:** Get construction workers to refer their mates to RateRight through a simple, trustworthy referral system that rewards both parties.

---

## 1. Program Mechanics

### Core Rewards Structure
- **Referrer Benefits:**
  - Priority job matching for 30 days from successful referral
  - $50 gift card after referee completes 20 hours of work

- **Referee Benefits:**
  - Priority job matching for 30 days from signup
  - $50 gift card after completing 20 hours of work

### Referral Tracking
- **Unique referral codes:** 8-character alphanumeric (e.g., `MIKE2024`, `DAVE8745`)
- **QR codes:** Generate dynamic QR codes that encode referral URLs
- **Attribution window:** 30 days from referral link click to signup

### Success Criteria
- **Completed referral:** Referee completes 20 hours of billable work within 90 days of signup
- **Reward trigger:** Automatic gift card issuance upon 20-hour milestone
- **Priority matching:** Immediate activation upon referral/signup

---

## 2. Technical Implementation

### Database Schema

```sql
-- Referrals tracking table
CREATE TABLE referrals (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    referrer_user_id UUID NOT NULL REFERENCES users(id),
    referee_user_id UUID REFERENCES users(id), -- NULL until signup
    referral_code VARCHAR(8) NOT NULL UNIQUE,
    referral_url TEXT NOT NULL,
    qr_code_url TEXT,
    
    -- Tracking fields
    clicks INTEGER DEFAULT 0,
    clicked_at TIMESTAMP[],
    signup_at TIMESTAMP,
    hours_worked DECIMAL(5,2) DEFAULT 0,
    conversion_completed_at TIMESTAMP,
    
    -- Rewards tracking
    referrer_reward_sent_at TIMESTAMP,
    referee_reward_sent_at TIMESTAMP,
    gift_card_codes JSONB, -- {referrer: "code", referee: "code"}
    
    -- Status tracking
    status VARCHAR(20) DEFAULT 'active', -- active, completed, expired
    
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Priority matching periods
CREATE TABLE priority_periods (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id),
    reason VARCHAR(50) NOT NULL, -- 'referral_made', 'referral_signup'
    referral_id UUID REFERENCES referrals(id),
    starts_at TIMESTAMP NOT NULL,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

-- Indexes
CREATE INDEX idx_referrals_code ON referrals(referral_code);
CREATE INDEX idx_referrals_referrer ON referrals(referrer_user_id);
CREATE INDEX idx_referrals_referee ON referrals(referee_user_id);
CREATE INDEX idx_priority_periods_user ON priority_periods(user_id, expires_at);
```

### Referral Code Generation
```javascript
// Generate unique 8-character codes
function generateReferralCode(userName) {
    const namePrefix = userName.slice(0, 4).toUpperCase();
    const randomSuffix = Math.floor(1000 + Math.random() * 9000);
    return `${namePrefix}${randomSuffix}`;
}

// Ensure uniqueness
async function createUniqueReferralCode(userId, userName) {
    let attempts = 0;
    while (attempts < 10) {
        const code = generateReferralCode(userName);
        const existing = await db.select().from(referrals).where(eq(referrals.referral_code, code));
        if (!existing.length) return code;
        attempts++;
    }
    // Fallback to UUID prefix
    return crypto.randomUUID().slice(0, 8).toUpperCase();
}
```

### Conversion Tracking
```javascript
// Track referee work hours
async function updateReferralProgress(refereeId, hoursWorked) {
    const referral = await db.select()
        .from(referrals)
        .where(eq(referrals.referee_user_id, refereeId))
        .where(eq(referrals.status, 'active'));
    
    if (referral && referral.hours_worked + hoursWorked >= 20) {
        // Complete the referral
        await completeReferral(referral.id);
    } else {
        await db.update(referrals)
            .set({ hours_worked: referral.hours_worked + hoursWorked })
            .where(eq(referrals.id, referral.id));
    }
}

async function completeReferral(referralId) {
    const referral = await db.select().from(referrals).where(eq(referrals.id, referralId));
    
    // Issue gift cards
    const giftCards = await issueGiftCards(referral.referrer_user_id, referral.referee_user_id);
    
    // Update referral status
    await db.update(referrals)
        .set({
            status: 'completed',
            conversion_completed_at: new Date(),
            referrer_reward_sent_at: new Date(),
            referee_reward_sent_at: new Date(),
            gift_card_codes: giftCards
        })
        .where(eq(referrals.id, referralId));
}
```

### Gift Card Fulfillment (Prezzee Integration)
```javascript
// Prezzee API integration
async function issueGiftCards(referrerId, refereeId) {
    const prezzeeAPI = new PrezzeeAPI(process.env.PREZZEE_API_KEY);
    
    const referrerCard = await prezzeeAPI.createGiftCard({
        amount: 50,
        currency: 'AUD',
        recipientEmail: await getUserEmail(referrerId),
        message: 'Thanks for referring a mate to RateRight!'
    });
    
    const refereeCard = await prezzeeAPI.createGiftCard({
        amount: 50,
        currency: 'AUD', 
        recipientEmail: await getUserEmail(refereeId),
        message: 'Welcome to RateRight! Thanks for joining through a mate.'
    });
    
    return {
        referrer: referrerCard.code,
        referee: refereeCard.code
    };
}
```

### Priority Job Matching
```javascript
// Check if user has active priority period
async function hasActivePriority(userId) {
    const priority = await db.select()
        .from(priority_periods)
        .where(eq(priority_periods.user_id, userId))
        .where(gte(priority_periods.expires_at, new Date()));
    
    return priority.length > 0;
}

// Modified job matching algorithm
async function getJobMatches(userId, jobPreferences) {
    const baseMatches = await findMatchingJobs(jobPreferences);
    
    if (await hasActivePriority(userId)) {
        // Boost score and prioritize in results
        return baseMatches.map(job => ({
            ...job,
            matchScore: Math.min(job.matchScore + 0.2, 1.0),
            isPriority: true
        })).sort((a, b) => b.matchScore - a.matchScore);
    }
    
    return baseMatches;
}
```

---

## 3. Marketing & Copy

### Program Name & Taglines
- **Program Name:** "Mates Rates"
- **Primary Tagline:** "Good mates share good work"
- **Alternative Taglines:**
  - "Refer a mate, help a mate"
  - "Better jobs for you and your mates"
  - "Share the work, share the rewards"

### SMS/Email Templates

**Referral Invitation SMS:**
```
G'day [Name]! 🔨

Your mate [ReferrerName] reckons you'd be perfect for RateRight - better construction jobs, better pay.

Use their code [CODE] and you'll both get priority job matching + $50 gift cards when you complete 20 hours.

Join here: rateright.com.au/join/[CODE]

Questions? Reply STOP to opt out.
```

**Referral Invitation Email:**
```
Subject: [ReferrerName] thinks you'd love these construction jobs

G'day [Name],

Your mate [ReferrerName] wanted you to know about RateRight - we match skilled tradies with quality construction work across Sydney.

Here's what [ReferrerName] said: "The jobs are legit, the pay is good, and they actually treat you like a professional."

**What you get:**
✅ Priority job matching for 30 days
✅ $50 gift card after 20 hours of work
✅ No dodgy jobs, no time wasters

**What [ReferrerName] gets:**
✅ Same priority matching & $50 gift card
✅ Knowing they helped a mate find better work

Ready to give it a crack? Use [ReferrerName]'s code: [CODE]

[JOIN NOW - rateright.com.au/join/[CODE]]

Cheers,
The RateRight Team
```

**Milestone Notification (10 hours worked):**
```
Subject: Halfway there! 🎯

Good work [Name]! You're 10 hours into your RateRight journey.

Complete another 10 hours and you'll both unlock your $50 gift cards.

[View your progress: app.rateright.com.au/referrals]
```

### QR Code Flyer Text
```
MATES RATES
Get your mates better construction work

SCAN → SIGN UP → GET PAID

✅ Priority job matching
✅ $50 gift card each
✅ No BS, just good work

Your code: [CODE]
rateright.com.au/join/[CODE]

Good mates share good work 🔨
```

---

## 4. Launch Plan

### Phase 1: Existing Workers (Week 1-2)
**Target:** 50 most active/satisfied workers

**Actions:**
1. **Personal outreach:** SMS to top performers explaining the program
2. **In-app announcement:** Prominent banner with "Invite a Mate" CTA
3. **Email campaign:** Detailed explanation with personal referral links
4. **Generate QR codes:** Physical flyers for job sites

**Success Metrics:**
- 30+ referral codes generated
- 10+ referee signups
- 5+ completed referrals (20 hours)

### Phase 2: All Active Workers (Week 3-4)
**Target:** All workers with >5 hours worked

**Actions:**
1. **App feature rollout:** Native referral sharing in user dashboard
2. **SMS blast:** Brief invitation with personalized codes
3. **Job site materials:** QR code stickers and flyers
4. **Incentive boost:** Limited-time bonus (e.g., $75 instead of $50)

**Success Metrics:**
- 100+ referral codes generated
- 25+ referee signups
- 15+ completed referrals

### Phase 3: New Signups (Ongoing)
**Target:** All new workers automatically enrolled

**Actions:**
1. **Onboarding integration:** Referral sharing as part of signup flow
2. **Welcome email:** Include personal referral code and sharing tools
3. **Progressive prompts:** Remind to refer mates after first successful job

**Success Metrics:**
- 100% participation rate (all new users get referral codes)
- 15% referral rate (15 referrals per 100 new users)
- 20% conversion rate (20% of referees complete 20 hours)

### Key Metrics to Track

**Acquisition Metrics:**
- Referral codes generated
- Unique clicks per code
- Signup conversion rate (clicks → signups)
- Time from click to signup

**Engagement Metrics:**
- Hours worked by referees
- Job application rate (referees vs. organic)
- Retention rate (referees vs. organic)
- Priority period utilization

**Conversion Metrics:**
- 20-hour completion rate
- Time to complete 20 hours
- Gift card redemption rate
- Referrer repeat behavior

**Financial Metrics:**
- Customer Acquisition Cost (CAC) via referrals
- Lifetime Value (LTV) of referred workers
- Program ROI (revenue generated vs. rewards paid)

### Tech Implementation Timeline

**Week 1:**
- Database schema deployment
- Basic referral code generation
- QR code generation service

**Week 2:**
- Prezzee API integration
- Priority matching algorithm updates
- Admin dashboard for tracking

**Week 3:**
- SMS/email template setup
- In-app referral sharing UI
- Analytics tracking implementation

**Week 4:**
- Full launch with monitoring
- A/B testing on messaging
- Performance optimization

---

## Success Indicators

**Short-term (Month 1):**
- 150+ active referral codes
- 50+ referee signups
- 25+ completed referrals
- 4.0+ referral rating (referee satisfaction)

**Medium-term (Month 3):**
- 20% of new signups via referrals
- 25% conversion rate (referees completing 20 hours)
- $40 average CAC via referrals (vs. $80 organic)
- 90%+ gift card redemption rate

**Long-term (Month 6):**
- Self-sustaining referral loop (referees become referrers)
- 30%+ signup share from referrals
- Referral workers show 15%+ higher LTV
- Program covers its own costs + generates profit

---

*This spec prioritizes simplicity and trust - core values for tradies. The program should feel like mates helping mates, not a corporate marketing scheme.*