Skip to main content

Overview

The Automation Engine allows you to create sophisticated multi-step workflows with conditions, delays, email sending, and tag/list management.

Automation Management

getAll

Retrieve all automation rules.
db.automations.getAll(): AutomationRule[]
automations
AutomationRule[]
Array of all automation rules
Example:
const automations = db.automations.getAll();
console.log(`Active automations: ${automations.filter(a => a.status === 'Active').length}`);

getById

Get a specific automation by ID.
db.automations.getById(id: string): AutomationRule | null
id
string
required
Automation ID
automation
AutomationRule | null
The automation rule if found

create

Create a new automation workflow.
db.automations.create(
  data: Omit<AutomationRule, 'id' | 'createdAt' | 'updatedAt' | 'stats'>
): AutomationRule
data.name
string
required
Automation name
data.description
string
Description of what this automation does
data.status
string
required
‘Active’ | ‘Paused’ | ‘Draft’
data.trigger
AutomationTrigger
required
Trigger configuration
data.nodes
AutomationNode[]
required
Array of workflow nodes
automation
AutomationRule
The created automation with generated ID and stats
Example:
const automation = db.automations.create({
  name: 'Welcome Series',
  description: 'Onboarding sequence for new subscribers',
  status: 'Active',
  trigger: {
    type: 'contact_added_to_list',
    listId: 'list_new_subscribers'
  },
  nodes: [
    {
      id: 'node_1',
      type: 'send_email',
      subject: 'Welcome to CAFH!',
      content: '<p>Welcome email content...</p>'
    },
    {
      id: 'node_2',
      type: 'wait',
      amount: 3,
      unit: 'days'
    },
    {
      id: 'node_3',
      type: 'send_email',
      subject: 'Getting Started Guide',
      content: '<p>Follow-up content...</p>'
    }
  ]
});

save

Update an existing automation.
db.automations.save(rule: AutomationRule): AutomationRule
rule
AutomationRule
required
Complete automation object with updates
automation
AutomationRule
The updated automation with new updatedAt timestamp

delete

Delete an automation.
db.automations.delete(id: string): void
id
string
required
Automation ID to delete

Execution

runForContact

Execute an automation for a single contact.
db.automations.runForContact(
  automationId: string,
  contact: Contact
): Promise<AutomationExecution>
automationId
string
required
ID of the automation to run
contact
Contact
required
The contact to run the automation for
execution
AutomationExecution
Execution record with complete log
Example:
const contact = db.crm.getById('c_12345');
if (contact) {
  const exec = await db.automations.runForContact('aut_123', contact);
  console.log('Execution status:', exec.status);
  console.log('Log:', exec.log);
}

runForSegment

Execute an automation for a segment of contacts.
db.automations.runForSegment(
  automationId: string,
  targetType: 'all' | 'subscribed' | 'list' | 'tag',
  targetValue?: string
): Promise<{ count: number; executions: AutomationExecution[] }>
automationId
string
required
ID of the automation to run
targetType
string
required
Type of segment to target
targetValue
string
List ID (if targetType=‘list’) or tag name (if targetType=‘tag’)
result
object
Count of contacts processed and array of executions
Example:
// Run for all subscribed contacts
const result = await db.automations.runForSegment(
  'aut_welcome',
  'subscribed'
);
console.log(`Processed ${result.count} contacts`);

// Run for specific list
const listResult = await db.automations.runForSegment(
  'aut_vip',
  'list',
  'list_vip_members'
);

getExecutions

Retrieve automation execution logs.
db.automations.getExecutions(): AutomationExecution[]
executions
AutomationExecution[]
Array of all executions (max 500)

Automation Node Types

Send Email Node

Send an email to the contact.
interface SendEmailNode {
  id: string;
  type: 'send_email';
  subject: string;
  content: string;
  fromName?: string;
}
Example:
{
  id: 'node_1',
  type: 'send_email',
  subject: 'Welcome!',
  content: '<h1>Welcome</h1>',
  fromName: 'CAFH Team'
}

Wait Node

Pause execution for a duration.
interface WaitNode {
  id: string;
  type: 'wait';
  amount: number;
  unit: 'minutes' | 'hours' | 'days';
}
Example:
{
  id: 'node_2',
  type: 'wait',
  amount: 2,
  unit: 'days'
}

Condition Node

Branch execution based on contact data or behavior.
interface ConditionNode {
  id: string;
  type: 'condition';
  check: 'email_opened' | 'email_clicked' | 'has_tag' | 'in_list';
  value?: string;
  branchTrue: AutomationNode[];
  branchFalse: AutomationNode[];
}
Example:
{
  id: 'node_3',
  type: 'condition',
  check: 'email_opened',
  branchTrue: [
    {
      id: 'node_4',
      type: 'update_tag',
      action: 'add',
      tag: 'Engaged'
    }
  ],
  branchFalse: [
    {
      id: 'node_5',
      type: 'send_email',
      subject: 'Are you still interested?',
      content: '<p>Re-engagement email...</p>'
    }
  ]
}

Update Tag Node

Add or remove tags from the contact.
interface UpdateTagNode {
  id: string;
  type: 'update_tag';
  action: 'add' | 'remove';
  tag: string;
}
Example:
{
  id: 'node_6',
  type: 'update_tag',
  action: 'add',
  tag: 'Newsletter Subscriber'
}

Move to List Node

Add contact to a list.
interface MoveToListNode {
  id: string;
  type: 'move_to_list';
  listId: string;
}
Example:
{
  id: 'node_7',
  type: 'move_to_list',
  listId: 'list_active_members'
}

End Node

Terminate the workflow.
interface EndNode {
  id: string;
  type: 'end';
}

Trigger Types

interface AutomationTrigger {
  type: AutomationTriggerType;
  listId?: string;        // For contact_added_to_list
  tag?: string;           // For tag_added
  campaignId?: string;    // For campaign events
  inactiveDays?: number;  // For no_activity
  scheduledAt?: string;   // For scheduled_date
}

type AutomationTriggerType =
  | 'contact_added_to_list'
  | 'tag_added'
  | 'campaign_sent'
  | 'campaign_opened'
  | 'campaign_clicked'
  | 'no_activity'
  | 'scheduled_date'
  | 'manual';

Complete Workflow Example

// Create a sophisticated re-engagement workflow
const reengagement = db.automations.create({
  name: 'Re-engagement Campaign',
  description: 'Win back inactive subscribers',
  status: 'Active',
  trigger: {
    type: 'no_activity',
    inactiveDays: 30
  },
  nodes: [
    {
      id: 'n1',
      type: 'send_email',
      subject: 'We miss you!',
      content: '<p>Haven\'t heard from you...</p>'
    },
    {
      id: 'n2',
      type: 'wait',
      amount: 3,
      unit: 'days'
    },
    {
      id: 'n3',
      type: 'condition',
      check: 'email_opened',
      branchTrue: [
        {
          id: 'n4',
          type: 'update_tag',
          action: 'add',
          tag: 'Re-engaged'
        },
        {
          id: 'n5',
          type: 'send_email',
          subject: 'Great to have you back!',
          content: '<p>Thanks for opening...</p>'
        }
      ],
      branchFalse: [
        {
          id: 'n6',
          type: 'update_tag',
          action: 'add',
          tag: 'Inactive'
        },
        {
          id: 'n7',
          type: 'move_to_list',
          listId: 'list_inactive'
        }
      ]
    },
    {
      id: 'n8',
      type: 'end'
    }
  ]
});

// Execute for inactive segment
const result = await db.automations.runForSegment(
  reengagement.id,
  'tag',
  'Inactive'
);

console.log(`Processed ${result.count} inactive contacts`);

Types Reference

interface AutomationRule {
  id: string;
  name: string;
  description?: string;
  status: 'Active' | 'Paused' | 'Draft';
  trigger: AutomationTrigger;
  nodes: AutomationNode[];
  nodePositions?: Record<string, { x: number; y: number }>;
  createdAt: string;
  updatedAt: string;
  stats: {
    totalExecutions: number;
    completed: number;
    emailsSent: number;
    tagsApplied: number;
  };
}

interface AutomationExecution {
  id: string;
  automationId: string;
  contactId: string;
  contactEmail: string;
  startedAt: string;
  completedAt?: string;
  currentStep: number;
  status: 'running' | 'completed' | 'failed';
  log: string[];
}

Build docs developers (and LLMs) love