Marketing Automation
This document covers the marketing automation (journeys) capabilities of the CRM & Marketing Platform.
Journey Builder
Multi-step automated sequences triggered by events or schedules.
┌─────────────────────────────────────────────────────────────────┐
│ NEW MEMBER ONBOARDING JOURNEY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [TRIGGER: member.created] │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ SEND Welcome │ │
│ │ Email │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ WAIT 3 days │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ YES ┌─────────────────┐ │
│ │ CONDITION: │───────────▶│ SEND Tips Email │ │
│ │ Opened welcome? │ └─────────────────┘ │
│ └────────┬────────┘ │
│ │ NO │
│ ▼ │
│ ┌─────────────────┐ │
│ │ SEND SMS │ │
│ │ Reminder │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ WAIT 7 days │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ END │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Event Triggers
| Trigger Event | Source | Possible Actions |
|---|---|---|
member.created | SCL | Welcome sequence |
teetime.booked | TeeTime | Booking confirmation |
teetime.completed | TeeTime | Review request |
handicap.updated | TeeTime | Congratulations message |
payment.failed | SCL | Payment reminder |
engagement.dropped | CRM | Win-back campaign |
competition.published | TeeTime | Tournament promotion |
churn.risk.high | CRM | Retention sequence |
Journey Step Types
| Type | Description | Configuration |
|---|---|---|
| TRIGGER | Entry point | eventType, conditions |
| SEND | Send message | channel, templateId |
| WAIT | Delay next step | duration (e.g., "3 days") |
| CONDITION | Branch based on criteria | rules, nextStepYes, nextStepNo |
| SPLIT | A/B test | variants[], weights |
| UPDATE | Update profile | field, value |
| END | Terminate journey | - |
Step Configuration Examples
SEND Step
{
"type": "SEND",
"name": "Welcome Email",
"config": {
"channel": "EMAIL",
"templateId": "welcome-email-v2"
},
"nextStepId": "step_wait_3d"
}
WAIT Step
{
"type": "WAIT",
"name": "Wait 3 Days",
"config": {
"duration": "3 days"
},
"nextStepId": "step_condition"
}
Supported duration formats:
"30 minutes""2 hours""3 days""1 week"
CONDITION Step
{
"type": "CONDITION",
"name": "Check Email Opened",
"config": {
"rules": [
{ "field": "lastEmailOpenAt", "operator": "isNotNull" }
],
"combinator": "AND"
},
"nextStepYesId": "step_tips",
"nextStepNoId": "step_sms"
}
SPLIT Step (A/B Test)
{
"type": "SPLIT",
"name": "A/B Test Subject Line",
"config": {
"variants": [
{ "name": "A", "weight": 50 },
{ "name": "B", "weight": 50 }
]
},
"nextStepAId": "step_variant_a",
"nextStepBId": "step_variant_b"
}
UPDATE Step
{
"type": "UPDATE",
"name": "Mark as Onboarded",
"config": {
"updates": [
{ "field": "tags", "operation": "add", "value": "onboarded" },
{ "field": "lifecycleStage", "value": "CUSTOMER" }
]
},
"nextStepId": "step_end"
}
Journey Lifecycle
DRAFT ──▶ ACTIVE ──▶ PAUSED ──▶ ACTIVE
│ │ │
│ │ │
▼ ▼ ▼
Edit Enrolling Resume/Stop
Customers
Status Descriptions
| Status | Description |
|---|---|
| DRAFT | Being built, not enrolling |
| ACTIVE | Enrolling customers, processing steps |
| PAUSED | Stopped enrolling, existing continue |
| ARCHIVED | Disabled, no activity |
Enrollment
Automatic (Trigger-based)
When a matching event occurs:
// Event: member.created with tier = "Gold"
// Journey: trigger = "member.created", conditions = [tier eq "Gold"]
// 1. Event received
// 2. Match against active journeys
// 3. Check trigger conditions
// 4. If match, enroll customer
// 5. Queue first step
Manual
await enrollCustomer(journeyId, customerId);
Re-entry
| Setting | Behavior |
|---|---|
allowReentry: false | Customer can only be enrolled once |
allowReentry: true | Customer can re-enter after completion |
Journey Engine
Processing Flow
1. Enrollment created
2. First step queued
3. Step processor picks up job
4. Execute step (send, wait, etc.)
5. Determine next step
6. Queue next step or complete
Wait Step Processing
WAIT steps are handled by a cron job:
// Every minute, check for expired waits
const expiredEnrollments = await findEnrollments({
status: 'ACTIVE',
waitingUntil: { lte: now() }
});
for (const enrollment of expiredEnrollments) {
await progressToNextStep(enrollment);
}
Journey Stats
| Metric | Description |
|---|---|
totalEnrolled | Total ever enrolled |
totalCompleted | Completed journey |
totalExited | Exited early |
activeCount | Currently in journey |
Per-Step Stats
| Metric | Description |
|---|---|
entered | Reached this step |
completed | Finished this step |
avgDuration | Time in step |
Exit Conditions
Customers can exit a journey:
- Completed - Reached END step
- Manual exit - Admin removes them
- Unsubscribed - Opted out during journey
- Merged - Profile merged into another
- Failed - Step execution failed