Sequences
Build automated drip campaigns with delays, conditions, and event-based triggers.
Sequences are automated email workflows that send a series of emails to contacts over time. They are the core of Kraiter's automation capabilities — use them for onboarding flows, nurture campaigns, re-engagement series, and more.
A sequence is defined using a YAML format that specifies triggers, steps, delays, conditions, and exit conditions.
Creating a sequence
Create a sequence by providing a name and a YAML definition:
const sequence = await kraiter.sequences.create({
name: 'onboarding',
definition: `
trigger:
event: signup.completed
steps:
- action: email
template: welcome-email
- action: delay
duration: 1d
- action: email
template: getting-started
- action: delay
duration: 3d
- action: condition
property: contact.properties.hasCompletedOnboarding
operator: equals
value: true
onTrue: exit
- action: email
template: onboarding-reminder
`,
});YAML format
The sequence definition has three top-level keys: trigger, steps, and optionally exitConditions.
Trigger
The trigger determines how contacts are enrolled in the sequence. There are two trigger types:
Event-based trigger — Enrols contacts automatically when a matching event is tracked:
trigger:
event: purchase.completedAPI trigger — Contacts are enrolled manually via the API (no automatic enrolment):
trigger:
api: trueSteps
Steps are executed in order for each enrolled contact. There are three step types:
Email step
Sends an email using a named template:
- action: email
template: welcome-emailThe template must exist before the sequence is activated. The email is sent using the contact's email address and their properties are available as Liquid variables.
Delay step
Pauses the sequence for a specified duration before continuing to the next step:
- action: delay
duration: 3dSupported duration units:
| Unit | Example | Description |
|---|---|---|
m | 30m | Minutes |
h | 2h | Hours |
d | 3d | Days |
w | 1w | Weeks |
You can combine units: 1d12h means one day and twelve hours.
Condition step
Evaluates a condition and branches based on the result. If the condition is true, the onTrue action is taken; otherwise, the sequence continues to the next step.
- action: condition
property: contact.properties.isVip
operator: equals
value: true
onTrue: skipAvailable actions for onTrue:
- exit — Remove the contact from the sequence
- skip — Skip the next step and continue
Condition operators:
| Operator | Types | Description |
|---|---|---|
equals | all | Exact match |
notEquals | all | Not equal |
contains | string | String contains substring |
greaterThan | number, date | Greater than |
lessThan | number, date | Less than |
exists | all | Property has a value |
notExists | all | Property has no value |
You can also check segment membership in a condition:
- action: condition
segment: high-value-customers
onTrue: exitExit conditions
Exit conditions are evaluated before each step. If any exit condition is true, the contact is removed from the sequence immediately. This is useful for stopping a sequence when the contact's situation changes.
exitConditions:
- property: contact.unsubscribed
operator: equals
value: true
- property: contact.properties.hasConverted
operator: equals
value: trueComplete example
Here is a full sequence definition for a trial expiry campaign:
trigger:
event: trial.started
exitConditions:
- property: contact.properties.plan
operator: notEquals
value: "trial"
steps:
- action: email
template: trial-welcome
- action: delay
duration: 3d
- action: email
template: trial-tips
- action: delay
duration: 4d
- action: condition
property: contact.properties.activatedFeature
operator: equals
value: true
onTrue: skip
- action: email
template: trial-feature-prompt
- action: delay
duration: 5d
- action: email
template: trial-expiring-soon
- action: delay
duration: 2d
- action: email
template: trial-expiredThis sequence:
- Sends a welcome email immediately when a trial starts
- Follows up with tips after three days
- Checks whether the user has activated a feature — if yes, skips the prompt
- Sends an expiry warning at day twelve
- Sends a final email at day fourteen
- Exits early if the contact upgrades from the trial plan
Sequence status management
Sequences have four statuses:
| Status | Description |
|---|---|
draft | Newly created. Cannot enrol contacts. Edit freely. |
active | Live and accepting enrolments. Steps are being processed. |
paused | Temporarily stopped. Existing enrolments are frozen. No new enrolments. |
archived | Permanently deactivated. Cannot be reactivated. |
Transition the status via the API:
// Activate a draft sequence
await kraiter.sequences.activate('onboarding');
// Pause an active sequence
await kraiter.sequences.pause('onboarding');
// Resume a paused sequence
await kraiter.sequences.activate('onboarding');
// Archive a sequence permanently
await kraiter.sequences.archive('onboarding');When a sequence is paused, contacts already in the sequence remain at their current step. When reactivated, processing resumes from where it left off. Archiving is permanent — archived sequences cannot be reactivated.
Enrolling contacts manually
For sequences with an API trigger, enrol contacts explicitly:
await kraiter.sequences.enrol('onboarding', {
email: 'alice@example.com',
});curl -X POST https://api.kraiter.com/sequences/onboarding/enrolments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "alice@example.com" }'A contact can only be enrolled in the same sequence once. If they have already completed or exited the sequence, they can be re-enrolled.
Dry-run testing
Before activating a sequence, test it with a dry run. A dry run simulates the sequence execution without actually sending emails:
const result = await kraiter.sequences.dryRun('onboarding', {
email: 'test@example.com',
});
console.log(result.steps); // Shows what would happen at each stepThis helps you verify that conditions, delays, and exit conditions behave as expected before going live.