Referral & Advocacy Engine
Referral & Advocacy Engine
The Referral & Advocacy Engine automates outreach to existing clients at key lifecycle moments — tenancy renewals, sale completions, and contact anniversaries — to generate Google reviews, new referrals, and repeat instructions. No manual workflow setup is required.
How It Works
- Agents record contact outcomes via the existing outcomes system (e.g.
renewed_tenancy,sold). - The daily trigger scanner (runs at 04:00 UTC) detects qualifying outcomes and lifecycle events across all contacts.
- A 3-email referral sequence is generated by the existing Content Writer AI using the agency's brand profile and category-specific context.
- Agents review and approve the sequence via the existing email review UI.
- Sequences are delivered via the existing email delivery infrastructure.
- Agents record outcomes (review received, referral added, etc.) from the trigger log.
- The referral dashboard tracks aggregate performance over time.
Trigger Types
| Trigger | Qualifying Condition | Default Window |
|---|---|---|
| Tenancy Renewal | active_tenant contact with renewed_tenancy outcome | Last 7 days |
| Sale Completion | active_seller/buyer contact with sold or listed_property outcome | Last 7 days |
| 12-Month Anniversary | Contact assigned a category 11–13 months ago | Configurable |
Suppression & Deduplication
Before firing a trigger, the scanner checks:
- Email suppression list — suppressed addresses are skipped.
- Marketing preferences — contacts who have opted out are excluded.
- Recent trigger deduplication — the
minDaysBetweenTriggerssetting prevents a contact from receiving multiple referral sequences within a short period. - Active journey conflict — contacts already in a running journey are not triggered.
Referral Dashboard
Navigate to Dashboard → Referral & Advocacy (/dashboard/referral) to view:
KPI Cards
- Sequences fired — total referral sequences generated in the selected period
- Reviews received — count and review rate percentage
- Referrals generated — new contacts attributed to referral campaigns
- Repeat instructions — repeat business won through advocacy outreach
Breakdowns
- Triggers by Type — sequences generated per lifecycle event type
- Outcomes Breakdown — results recorded by agents (review received, referral added, repeat instruction, testimonial received, no action)
Recent Trigger Log
A table of the most recent trigger fires showing contact name (linked to contact profile), trigger type, contact category, and the date fired. Select a time period of 30, 90, 180, or 365 days.
Configuring Triggers
Navigate to Settings → Referral (/dashboard/settings/referral) to configure each trigger type independently.
Per-Trigger Settings
| Setting | Description |
|---|---|
| Enabled | Toggle the trigger on or off for your organisation |
| Google Review URL | Link included in review-request emails |
| Referral Form URL | Link to your agency's referral submission form |
| Anniversary Months | The month window used for the 12-Month Anniversary trigger |
| Custom AI Context | Additional context passed to the Content Writer for this trigger type |
Changes take effect at the next daily scan.
Recording Outcomes
After a referral sequence is sent, agents record what happened via the trigger log:
| Outcome | Description |
|---|---|
review_received | Client left a Google or other review |
referral_contact_added | A new contact was added as a referral |
repeat_instruction | Client re-instructed the agency |
testimonial_received | Client provided a written testimonial |
no_action | No response or follow-up action |
Manual Trigger (Admin Only)
Admins can manually fire a referral sequence for a specific contact using the referral.triggerManual tRPC endpoint or via the contact profile (if surfaced in the UI). This is useful for contacts who were missed by the automated scanner or who should receive an out-of-cycle sequence.
tRPC API Reference
All endpoints are under the referral router and require an authenticated session. Endpoints marked admin only require the admin role.
referral.getConfig
Returns all three trigger configurations for the current organisation, with defaults applied where no config exists.
// No input required
const config = await trpc.referral.getConfig.query();
Response: Array of trigger config objects with fields: triggerType, enabled, anniversaryMonths, minDaysBetweenTriggers, googleReviewUrl, referralFormUrl, customAiContext.
referral.updateConfig (admin only)
Upserts a trigger configuration for the current organisation.
await trpc.referral.updateConfig.mutate({
triggerType: "tenancy_renewal",
enabled: true,
googleReviewUrl: "https://g.page/r/your-review-link",
referralFormUrl: "https://youragency.com/refer",
minDaysBetweenTriggers: 180,
});
referral.listTriggerLog
Returns a paginated list of trigger log entries with associated contact details.
const log = await trpc.referral.listTriggerLog.query({
limit: 20,
offset: 0,
daysBack: 90,
});
// log.items — array of trigger log entries
// log.total — total count
referral.recordOutcome
Records an agent-supplied outcome against a trigger log entry.
await trpc.referral.recordOutcome.mutate({
triggerLogId: "<uuid>",
outcomeType: "review_received",
notes: "Left a 5-star Google review on 14 Jul",
});
outcomeType values: review_received · referral_contact_added · repeat_instruction · testimonial_received · no_action
referral.getStats
Returns aggregated performance statistics for the organisation.
const stats = await trpc.referral.getStats.query({ daysBack: 90 });
// stats.totals — { triggersFired, reviewsReceived, referralsGenerated, repeatInstructions, responseRate, reviewRate }
// stats.byTriggerType — [{ triggerType, count }]
// stats.byOutcomeType — [{ outcomeType, count }]
referral.triggerManual (admin only)
Manually fires a referral sequence for a specific contact.
await trpc.referral.triggerManual.mutate({
contactId: "<uuid>",
triggerType: "anniversary_12_month",
});
referral.listOutcomes
Lists recorded outcomes filtered by trigger log entry or contact.
const outcomes = await trpc.referral.listOutcomes.query({
triggerLogId: "<uuid>", // or
contactId: "<uuid>",
});
Database Schema
Tables
referral_trigger_configs
One row per org per trigger type. Stores all per-trigger settings. Missing rows fall back to system defaults.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
orgId | text | Organisation identifier |
triggerType | enum | tenancy_renewal · sale_completion · anniversary_12_month |
enabled | boolean | Whether this trigger is active |
anniversaryMonths | integer | Month window for anniversary trigger |
minDaysBetweenTriggers | integer | Minimum days before re-triggering the same contact |
googleReviewUrl | text | Google Review link |
referralFormUrl | text | Referral submission form link |
customAiContext | text | Additional context for Content Writer |
referral_trigger_log
Immutable audit log. One row per trigger fire per contact.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
orgId | text | Organisation identifier |
contactId | uuid | Linked contact |
triggerType | enum | Trigger that fired |
sourceOutcomeId | uuid | Outcome record that caused the trigger (nullable) |
journeyId | uuid | Generated journey ID |
firedAt | timestamp | When the trigger fired |
referral_outcomes
Agent-recorded results for each trigger log entry.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key |
triggerLogId | uuid | Linked trigger log entry |
contactId | uuid | Contact |
outcomeType | enum | Recorded outcome |
notes | text | Optional agent notes |
recordedAt | timestamp | When the outcome was recorded |
Deployment Checklist
After deploying v1.0.87, run the following before enabling the feature for users:
# 1. Apply schema migrations
npx drizzle-kit push
# 2. Seed referral journey templates (12 templates, one per category)
npx tsx src/db/seeds/referral-journey-templates.ts
The trigger scanner will begin firing automatically at the next 04:00 UTC cron run. To activate triggers for an organisation, an admin must enable at least one trigger type in Settings → Referral.