Steps
Steps and their properties in automation workflows.
How it works
Steps are the building blocks of automation workflows. They define the actions that will be executed when the automation runs.
The following steps are available:
Step properties
Every step in an automation has the following base properties:
keystringrequiredA unique identifier for the step. Used in connection definitions to connect steps.
typestringrequiredThe type of step. Possible values: trigger, send_email, delay, wait_for_event, condition, split, contact_update, contact_delete, add_to_segment.
configobjectrequiredThe configuration object for the step. The shape depends on the step type.
Below is a list of all the possible step types and their configurations.
trigger
The trigger step starts the automation when a matching event is received.
config.event_namestringrequiredThe name of the event that triggers the automation.
{
"key": "start",
"type": "trigger",
"config": {
"event_name": "user.created"
}
}send_email
Sends an email using a template.
config.templateobjectrequiredThe published template to send. Provide id and optionally variables.
config.template.idstringrequiredThe ID or alias of the template to send.
config.template.variablesobjectoptionalA key-value map of template variables. Each value can be a static string or a variable reference object ({ "var": "event.fieldName" }) that resolves dynamically from the event.*, contact.*, or wait_events.* namespaces.
config.fromstringoptionalThe sender email address. If provided, this value will override the template's default value.
config.subjectstringoptionalThe email subject line. If provided, this value will override the template's default value.
config.reply_tostringoptionalReply-to email address. If provided, this value will override the template's default value.
{
"key": "welcome",
"type": "send_email",
"config": {
"template": {
"id": "062f8ef4-fbfa-44f1-b5e0-ff8e1e8ffa96",
"variables": {
"name": { "var": "event.firstName" }
}
},
"from": "hello@example.com",
"subject": "Welcome!",
"reply_to": "support@example.com"
}
}delay
Pauses execution for a specified duration.
config.durationstringrequiredThe delay duration in natural language (e.g. "1 hour", "3 days"). Maximum: 30 days.
{
"key": "wait_1_hour",
"type": "delay",
"config": {
"duration": "1 hour"
}
}wait_for_event
Pauses execution until a specific event is received or a timeout is reached.
config.event_namestringrequiredThe name of the event to wait for.
config.timeoutstringoptionalThe maximum time to wait before timing out (e.g. "3 days", "1 hour"). Maximum: 30 days.
config.filter_ruleobjectoptionalAn optional rule object to filter incoming events.
{
"key": "wait_for_purchase",
"type": "wait_for_event",
"config": {
"event_name": "purchase.completed",
"timeout": "3 days"
}
}condition
Branches the workflow based on rules. Condition configs can be a single rule or a logical group (and/or) of rules.
config.typestringrequiredThe type of condition node: rule, and, or or.
config.fieldstringrequiredFor rule type — the field to evaluate. Must use the event. or contact. namespace prefix (e.g. event.amount, contact.email).
config.operatorstringrequiredFor rule type — the comparison operator: eq, neq, gt, gte, lt, lte, contains, starts_with, ends_with, exists, is_empty.
config.valuestring | number | boolean | nulloptionalFor rule type — the value to compare against. Not required for exists and is_empty operators.
config.rulesobject[]optionalFor and / or types — an array of nested condition config objects. Must contain at least one item.
{
"key": "check_plan",
"type": "condition",
"config": {
"type": "rule",
"field": "event.plan",
"operator": "eq",
"value": "pro"
}
}{
"key": "check_plan_and_amount",
"type": "condition",
"config": {
"type": "and",
"rules": [
{ "type": "rule", "field": "event.plan", "operator": "eq", "value": "pro" },
{ "type": "rule", "field": "event.amount", "operator": "gte", "value": 100 }
]
}
}split
A/B split: randomly routes contacts between two branches by percentage. Assignment is deterministic per contact+step (re-runs keep the same branch). Branch A rides the condition_met edge, branch B condition_not_met.
config.percentnumberrequiredShare of contacts taking branch A, an integer from 1 to 99.
{
"key": "ab",
"type": "split",
"config": {
"percent": 50
}
}contact_update
Updates a contact's fields. Each field value can be either a hardcoded value or a dynamic variable reference using the { "var": "..." } syntax, with the event.* or contact.* scope.
config.first_namestring | objectoptionalThe contact's first name. Accepts a hardcoded string or a variable reference.
config.last_namestring | objectoptionalThe contact's last name. Accepts a hardcoded string or a variable reference.
config.unsubscribedboolean | objectoptionalThe contact's unsubscribed status. Accepts a boolean or a variable reference.
config.propertiesobjectoptionalA map of custom contact properties to update. Each value can be a hardcoded value (string, number, boolean) or a variable reference.
{
"key": "update_contact",
"type": "contact_update",
"config": {
"properties": {
"company": { "var": "event.company" },
"vip": true
}
}
}contact_delete
Deletes the contact from the audience. This step does not require any configuration fields. Pass an empty object {} as the config.
{
"key": "remove_contact",
"type": "contact_delete",
"config": {}
}add_to_segment
Adds the contact to a segment.
config.segment_idstringrequiredThe ID of the segment to add the contact to.
{
"key": "add_to_vip",
"type": "add_to_segment",
"config": {
"segment_id": "83a1e324-26dc-47eb-9b28-ba8b6d1fe808"
}
}