Skip to content

Automated Sequences

Sequences are automated drip campaigns that enroll contacts based on trigger events. Each sequence contains ordered steps with configurable delays, supporting both email and SMS channels.

FieldTypeDescription
idUUIDPrimary key
foundation_idUUIDOwning foundation
namestringSequence name (e.g., “New Donor Welcome”)
triggerSequenceTriggerEvent that enrolls contacts
statusstringactive or paused

The SequenceTrigger enum defines which contact events automatically enroll contacts:

ValueDescription
donation_receivedContact makes a donation
application_submittedContact submits a scholarship application
subscriber_addedContact is assigned the subscriber relationship
donation_failedA recurring donation payment fails

Each sequence contains ordered SequenceStep records:

FieldTypeDescription
idUUIDPrimary key
sequence_idUUIDParent sequence
positionintegerOrder in the sequence (1-based)
channelCampaignChannelemail or sms
subjectstring?Email subject line (null for SMS)
bodystringMessage body (supports merge fields)
delay_hoursintegerHours to wait before executing this step

Steps are always ordered by position. The delay_hours on each step is relative to enrollment time (step 1) or the previous step’s execution.

PositionChannelDelaySubjectBody
1Email0 hoursThank you, (first_name)!Welcome email with donation receipt
2Email72 hoursYour impact at (foundation_name)Impact report / how funds are used
3SMS168 hoursQuick check-in text message

The SequenceService::enroll() method creates an enrollment record:

public function enroll(Contact $contact, Sequence $sequence): SequenceEnrollment;

The enrollment:

  1. Finds the first step (lowest position)
  2. Creates a SequenceEnrollment with status: active
  3. Sets next_step_at to now() + firstStep->delay_hours
  4. If the sequence has no steps, marks enrollment as completed immediately
FieldTypeDescription
idUUIDPrimary key
sequence_idUUIDThe sequence
contact_idUUIDThe enrolled contact
foundation_idUUIDFoundation scope
current_step_idUUID?The step currently queued
statusstringactive, completed, or cancelled
next_step_atdatetime?When the current step should execute
enrolled_atdatetimeWhen the contact was enrolled
completed_atdatetime?When the sequence finished

The SequenceService::processDue() method runs on a schedule (via Laravel’s scheduler or queue worker):

public function processDue(): void;

It:

  1. Finds all active enrollments where next_step_at <= now()
  2. Dispatches a ProcessSequenceStep job for each

The ProcessSequenceStep job:

  1. Sends the message via EmailService or SmsService based on the step’s channel
  2. Finds the next step in the sequence (by position)
  3. If a next step exists, updates current_step_id and next_step_at
  4. If no next step exists, marks the enrollment as completed

Sequence step bodies support the same merge placeholders as campaigns and templates: first_name, last_name, and foundation_name. See Message Templates for the full reference.

PlanMax sequences
Starter2
Growth10
ProUnlimited
MethodPathDescription
GET/api/sequencesList sequences
POST/api/sequencesCreate a sequence
GET/api/sequences/{id}Show a sequence with steps
PUT/api/sequences/{id}Update a sequence
DELETE/api/sequences/{id}Delete a sequence
POST/api/sequences/{id}/stepsAdd a step to a sequence
PUT/api/sequences/{id}/steps/{step}Update a step
DELETE/api/sequences/{id}/steps/{step}Delete a step