Actions

Actions define what happens when a trigger rule’s conditions are met. The @repo/trigger-rules package supports various action types that can be performed in response to events.

Action Structure

An action has the following structure:

interface Action {
  type: string;           // The type of action to perform
  [key: string]: any;     // Additional properties specific to the action type
}

Each action type has its own set of required and optional properties.

Available Action Types

Email Actions

Send emails to users or administrators:

{
  "type": "email",
  "template": "welcome-email",
  "recipient": "{{user.email}}",
  "subject": "Welcome to our platform!",
  "data": {
    "userName": "{{user.name}}",
    "companyName": "Zopio"
  }
}
PropertyDescriptionRequired
templateEmail template IDYes
recipientEmail recipientYes
subjectEmail subjectNo (can be defined in template)
dataTemplate variablesNo
ccCarbon copy recipientsNo
bccBlind carbon copy recipientsNo

Notification Actions

Send notifications to users or teams:

{
  "type": "notification",
  "target": "admin",
  "channel": "slack",
  "message": "New user signed up: {{user.email}}",
  "priority": "high"
}
PropertyDescriptionRequired
targetNotification target (user ID, role, or team)Yes
channelNotification channel (slack, email, in-app)Yes
messageNotification messageYes
priorityNotification priority (low, medium, high)No
dataAdditional data for the notificationNo

Webhook Actions

Send HTTP requests to external services:

{
  "type": "webhook",
  "url": "https://api.example.com/webhook",
  "method": "POST",
  "headers": {
    "Authorization": "Bearer {{env.API_KEY}}",
    "Content-Type": "application/json"
  },
  "payload": {
    "event": "user_created",
    "userId": "{{user.id}}",
    "timestamp": "{{now}}"
  }
}
PropertyDescriptionRequired
urlWebhook URLYes
methodHTTP method (GET, POST, PUT, DELETE)Yes
headersHTTP headersNo
payloadRequest payloadNo
timeoutRequest timeout in millisecondsNo

Function Actions

Execute a JavaScript function:

{
  "type": "function",
  "name": "processUserData",
  "args": {
    "userId": "{{user.id}}",
    "data": "{{user}}"
  }
}
PropertyDescriptionRequired
nameFunction name (must be registered)Yes
argsFunction argumentsNo

Functions must be registered before they can be used:

import { registerFunction } from "@repo/trigger-rules";

registerFunction("processUserData", async (args) => {
  const { userId, data } = args;
  // Process user data
  return { success: true };
});

Database Actions

Perform database operations:

{
  "type": "database",
  "operation": "update",
  "table": "users",
  "where": {
    "id": "{{user.id}}"
  },
  "data": {
    "lastActive": "{{now}}",
    "status": "active"
  }
}
PropertyDescriptionRequired
operationDatabase operation (insert, update, delete, query)Yes
tableDatabase table nameYes
whereCondition for update/delete/queryDepends on operation
dataData for insert/updateDepends on operation
returningFields to returnNo

Event Actions

Trigger another event:

{
  "type": "event",
  "name": "user.profile.updated",
  "payload": {
    "userId": "{{user.id}}",
    "changes": "{{event.changes}}"
  }
}
PropertyDescriptionRequired
nameEvent nameYes
payloadEvent payloadYes
delayDelay in milliseconds before triggeringNo

Log Actions

Log information for debugging or auditing:

{
  "type": "log",
  "level": "info",
  "message": "User {{user.id}} triggered rule {{rule.id}}",
  "data": {
    "user": "{{user}}",
    "timestamp": "{{now}}"
  }
}
PropertyDescriptionRequired
levelLog level (debug, info, warn, error)Yes
messageLog messageYes
dataAdditional data to logNo

Template Variables

Actions support template variables that are replaced with values from the event data or environment:

Event Data Variables

Access event data using the {{field.path}} syntax:

{
  "type": "email",
  "recipient": "{{user.email}}",
  "subject": "Welcome, {{user.name}}!"
}

Special Variables

Special variables provide access to system values:

VariableDescriptionExample
{{now}}Current timestamp"timestamp": "{{now}}"
{{rule.id}}Current rule ID"ruleId": "{{rule.id}}"
{{rule.name}}Current rule name"ruleName": "{{rule.name}}"
{{env.VARIABLE}}Environment variable"apiKey": "{{env.API_KEY}}"

Internationalization Support

Actions can include internationalization support for messages and content:

{
  "type": "notification",
  "target": "user",
  "channel": "in-app",
  "message": {
    "en": "Welcome to our platform!",
    "es": "¡Bienvenido a nuestra plataforma!",
    "fr": "Bienvenue sur notre plateforme !"
  }
}

The appropriate message will be selected based on the user’s locale or system default.

Custom Action Types

You can extend the rule engine with custom action types by registering them:

import { registerActionType } from "@repo/trigger-rules";

// Register a custom action type
registerActionType("sms", async (action, context) => {
  const { to, message } = action;
  const phoneNumber = resolveTemplate(to, context);
  const smsMessage = resolveTemplate(message, context);
  
  // Send SMS using your SMS provider
  await smsService.send(phoneNumber, smsMessage);
  
  return { success: true };
});

// Now you can use it in your rules
const rule = {
  // ...
  "actions": [
    {
      "type": "sms",
      "to": "{{user.phoneNumber}}",
      "message": "Welcome to our platform, {{user.name}}!"
    }
  ]
  // ...
};

Action Execution

Actions are executed in the order they are defined in the rule. If an action fails, subsequent actions will still be executed unless you configure the rule to stop on failure.

To configure failure behavior:

{
  "type": "webhook",
  "url": "https://api.example.com/webhook",
  "method": "POST",
  "payload": {
    "event": "user_created",
    "userId": "{{user.id}}"
  },
  "stopOnFailure": true
}

Best Practices

  1. Keep actions focused - Each action should have a clear, specific purpose
  2. Use template variables - Make your actions dynamic with template variables
  3. Handle failures - Consider what should happen if an action fails
  4. Test thoroughly - Validate your actions with different inputs
  5. Use internationalization - Support multiple languages where appropriate

Examples

Send Welcome Email and Notify Sales Team

{
  "actions": [
    {
      "type": "email",
      "template": "welcome-email",
      "recipient": "{{user.email}}",
      "data": {
        "userName": "{{user.name}}",
        "planName": "{{user.plan.name}}"
      }
    },
    {
      "type": "notification",
      "target": "sales",
      "channel": "slack",
      "message": "New user signed up: {{user.email}} ({{user.plan.name}} plan)"
    }
  ]
}

Update User Status and Log Activity

{
  "actions": [
    {
      "type": "database",
      "operation": "update",
      "table": "users",
      "where": {
        "id": "{{user.id}}"
      },
      "data": {
        "status": "active",
        "lastLoginAt": "{{now}}"
      }
    },
    {
      "type": "log",
      "level": "info",
      "message": "User {{user.id}} logged in",
      "data": {
        "userId": "{{user.id}}",
        "timestamp": "{{now}}",
        "ip": "{{event.ip}}"
      }
    }
  ]
}

See Also