Courier's Automations let you trigger a series of steps –like send, delay, update profile, fetch-data– where each step represents a specific action that the automation will execute on your behalf when an event is sent to the Automation API.

Automations can be defined and triggered ad-hoc with a single API call or by calling a re-usable Automation template defined in the Automations designer.


Topics

Structuring an automation

Automation templates

Triggering an automation

Examples

Automation data logs


Structuring an Automation

  • There are six step types that can be used to build an automation: Send, Send-list, Fetch-Data, Delay, Update-Profile, Cancellation

  • There are two ways to create and trigger an automation to a recipient or list of recipients: on a one-off ad hoc basis using the /invoke endpoint or by triggering a reusable automation template created in the Courier Designer via the /template/invoke endpoint.

Automation Steps

An automation step represents a specific action that the automation will execute on your behalf.

Send

A send step will deliver a single notification to a recipient. The recipient and template properties are required. Template refers to the event or Notification ID of the notification to be sent, and recipient refers to any nonempty Recipient ID that you can define to keep track of and identify the notification's recipient across messages.

{
"action": "send",
"data": {}, // optional
"if": "<CONDITIONAL_EXPRESSION>", // optional javascript boolean
expression
"override": {}, // optional: send provider override
"profile": {}, // optional
"recipient": "<RECIPIENT_ID">,
"ref": "<REFERENCE>" // optional
"template": "<TEMPLATE_ID>"
"idempotency_expiry": "<IDEMPOTENT_EXPIRATION>", // optional
"idempotency_key": "<IDEMPOTENT_KEY>" // optional
}

Send List

A send-list step will deliver a message to a list of recipients. The list and template properties are required. See the article Lists API & List ID Pattern guidelines for more information on lists.

{
"action": "send-list",
"brand": "<BRAND_ID>", // optional
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
"override": {}, // optional: send provider override
"data": {}, // optional
"list": "<LIST_ID>",
"template": "<TEMPLATE_NAME_OR_ID>",
"data_source": { // optional
"webhook": {
"body": {}, // optional
"headers": {}, // optional
"params": {}, // optional
"method": "GET" | "POST", // optional, default GET
"url": "<API_RESOURCE>"
},
"merge_strategy": "replace|overwrite|soft-merge|none"
},
"idempotency_expiry": "<IDEMPOTENT_EXPIRATION>", // optional
"idempotency_key": "<IDEMPOTENT_KEY>" // optional
}

  • You can use the data-source property to define an API resource to be used to render a notification template. If using data-source, a merge strategy and a webhook with a url must be given.

  • The data_source.webhooks.url should accept a recipientId query string parameter.

  • The response from the data_source property will be merged with the existing automation data that was defined at runtime, based on the merge strategy, and will be passed to the notification template as the data property. See more on the different merge strategies under the Update-Profile section.

Send Idempotency features

send and send-list steps support idempotency for safely retrying requests without accidentally performing the same operation twice.

To define an idempotent send or send-list step, provide an idempotency_key property on the step. An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions.

In addition to the idempotency_key , you can define an idempotency_expiry that allows you to set an expiration on the idempotency_key that is longer than 24 hours (up to 1 year). See Idempotent Requests for more on Idempotency.

Example: Idempotent send step.

{
action: "send",
recipient: "example@emaildomain.com",
template: "Idempotence",
idempotency_key: "abcd-1234",
idempotency_expiry: 1618947104 //expiration date in epoch time
}

Fetch-Data

A fetch-data step will fetch data from an API resource and store it into run context to be used for subsequent step executions. webhook and merge_strategy are required.

{
"action": "fetch-data",
"webhook": {
"body": {}, // optional
"headers": {}, // optional
"params": {}, // optional
"method": "GET" | "POST", // optional, default GET
"url": "<API_RESOURCE>"
},
"merge_strategy": "replace|overwrite|soft-merge|none",
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>", // optional
"idempotency_expiry": "<IDEMPOTENT_EXPIRATION>", // optional
"idempotency_key": "<IDEMPOTENT_KEY>" // optional
}

The response from the fetch-data step will be merged with the existing automation data that was defined at runtime, based on the merge strategy, and will be passed to the notification template as the data property.

Delay

Important: When using the delay step, an automation will be processed serially. Each item in the automation is processed one at a time and the next step will not be undertaken until the current one has completed.

Note: There is a 5-15 minute variance in when delay step actions will finish processing.

There are two ways to delay an automation step

  • Delay until a specific time

  • Delay for a period of time

Delay until a specific time

To delay a step until a specific time, set the time using an ISO-8601 timestamp

{
"action": "delay",
"until": "2021-02-18T18:40:05.960Z", // ISO-8601timestamp
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
}

Delay for a period of time

You are able to delay an automation step for the following whole increments: -

  • minute(s)

  • hours(s)

  • day(s)

  • month(s)

{ 
"action": "delay",
"duration": "1 hour",
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
}

Update-Profile

An update-profile step will update the recipient's profile according to the "merge" strategy provided in the step. recipient_id, profile, and merge are required.

{ 
"action": "update-profile",
"recipient_id": "<RECIPIENT_ID>",
"profile": {},
"merge": "replace|overwrite|soft-merge|none",
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
}

Merge strategy definitions:

In the following definitions, A = a profile attribute defined in the step; B = an existing profile in Courier.

  • Replace: overwrites all properties in B from A; remove properties in B that do not exist in A

  • Overwrite: overwrite all properties in B from A

  • Soft-merge: only overwrite properties in B from A that do not yet exist in B

  • None: No changes to B if B already exists; else B = A

Invoke

The invoke step allows you to execute another automation template. The template property is required, and the optional context object defines the data and properties to invoke the new, targeted template with.

{
"action": "invoke",
"template": "<TEMPLATE_ID>",
"context": { //optional
"brand": "<BRAND_ID>", // optional
"data": {}, // optional
"profile": {}, // optional
"template": "<NOTIFICATION_TEMPLATE>", // optional
"recipient": "<RECIPIENT_ID>", // optional
},
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
}

Cancel

Automations can be marked as cancelable by providing a cancelationToken then canceled by providing a cancelation token on a subsequent automation. All automations with a matching cancelation token will be canceled.

Providing a cancelationToken

{ 
"cancelationToken": "<CANCELATION_TOKEN>",
"steps": [
// ... step configuration
]
}

If you want to cancel automation on a per-recipient basis there are two options:

  1. Use Ad Hoc automation and provide a unique cancelationToken per recipient

  2. OR Use an automation template and set a dynamic cancellation token each time you invoke the automation like this:

    {
    "cancelation_token": {
    "$ref": "data.foo.token"
    },
    "steps": [
    {
    "action": "",
    "template": "",
    "recipient": "",
    "profile": {
    "email": ""
    }
    },
    ]
    }

Cancelling automations using a cancelationToken

{ 
"steps": [
{
"action": "cancel",
"cancelationToken": "<CANCELATION_TOKEN>",
"if": "<CONDITIONAL_EXPRESSION>", // optional boolean expression
"ref": "<REFERENCE>" // optional
}
]
}

Step Conditionals

You can define conditions that will determine if a step is executed or not. Adding an if property to a step makes it a conditional step. The value of the if property should be a valid javascript expression that evaluates to a boolean. Properties set in the run context are available for use in these expressions.

For example, the following send step has a conditional expression that should evaluate to true. Therefore, the step will be executed.

{
"template": "TEST",
"recipient": "abcd-1234-efgh-5678",
"profile": {
"email": "test@gmail.com"
},
"data": {
"foo": "send-it"
},
"automation": {
"steps": [
{
"action": "send",
"if": "data.foo === 'send-it'"
}
]
}
}

Step References and Conditionals

You can define a step level reference, by adding a ref property to a step definition.

In the conditionals of subsequent steps, you can then reference metadata about the sent message using the word "refs."

For example, if you only want to send a follow-up message if that message hasn't been opened yet, you can define the following automation run:

{
"automation": {
"steps": [
{
"action": "send",
"template": "OUTREACH",
"ref": "outreach"
},
{
"action": "delay",
"delayFor": "24 hours"
},
{
"action": "send",
"template": "FOLLOWUP",
"ref": "followup",
"if": "refs.outreach.status < MessageStatus.Opened"
},
]
}
}

In the above example, refs.outreach allows us to access information in the step context of the first send step. For send steps, this step context includes information about the status of the send notification.

Run-Step Composition

There are a few object properties that can be defined at both the step and the run level. Run level data and profile properties will compose into each step, with already provided step level properties taking precedence.

For example, the "Title" property will compose into and be available for each step.

{
[...]
"data": {
"Title": "Back to the Future"
}
"automation": {
"steps": [
{
[...]
"data": {
"Username": "Doc Brown"
}
},
{
[...]
"data": {
"Username": "Marty McFly"
}
},
[...]
]
}
}

Templates

You can pre-define a list of automation steps by creating an automation template in the Designer UI. Automation Templates support JSONNET.

You can create templates from scratch or start from one of the predefined templates for common use cases.

The template builder lets you create and save a reusable automation using a visual UI designer. You can also toggle between the visual design and a code editor to view and edit the automation in a code.

Note: Edits you make to an automation template will not apply retroactively to any recipients or lists already added to an automation run.

For more details on building automation templates with the visual designer see

Structure

Automation templates

// define global variables here
{
sources: ["<EVENT_NAME>"], // list of event source that this
template can be triggered by
steps: [], // a list of automation steps
}

At runtime, you can pass a data and/or profile property into your template.

//1.define the template to send to a list of users 
local list=data('users', []);
{
steps: [
{
action: "send",
profile: {
email: email
},
recipient: item.userId,

}
for item in list
for email in item.email
]
}

//2.make the api call and provide the user list

{
event: "SEND-TO-USERS",
user: "abc-123",
//defaultrecipientdata: {
users: [
{
userId: "123-abc-123",
email: [
'user1@gmail.com',
'user1_altl@gmail.com'
]
},
{
userId: "abc-123-abc",
email: [
'user2@yahoo.com'
]
},

]
}
}

Triggering an Automation

To trigger an automation run, there are two apis that can be called with your Courier API token.

  • automations/invoke

  • automations/{templateId}/invoke

Trigger an ad hoc automation via /invoke

POST - /automations/invoke

Invoke an ad hoc automation run, by providing a valid automation definition in the request body.

Structure

{
"brand": "<BRAND_ID>", // optional: brand id
"template": "<TEMPLATE_NAME_OR_ID>", //optional
"recipient": "<RECIPIENT_ID>", //optional: user id for automation
"data": {}, //optional: root level data for the ad hoc automation
"profile": {},
//optional root level profile information for ad hoc
"automation": {
"cancelationToken": "<CANCELATION_TOKEN>",
//optional: can be used to later cancel the running automation
"steps": [
{
"action": "send",
"data": {}, //optional: uses root level data if not present
"profile": {},
//optional: uses root level profile if not present
"recipient": "<RECIPIENT_ID>",
//recipient of the message. will fallback to root recipient
"template": "<TEMPLATE_ID>",
//the notification template to use,
"brand": "<BRAND_ID>",
//optional: will use root level brand_id if not present
"override": {}, //optional: send provider override
"if": "<CONDITIONAL_EXPRESSION>",
//optional javascript boolean expression
//see send step documtenation above for more details
},
{
"action": "delay",
//either duration or until is required
//see delay step documentation above for more details
},
{
"action": "cancel",
"cancelationToken": "<CANCELATION_TOKEN>",
"if": "<CONDITIONAL_EXPRESSION>",
//optional javascript boolean expression
//see cancel step documentation above for more details
}
]
}
}

Trigger an automation template via /template/invoke

POST - /automations/{templateId}/invoke

Structure

{
"template": "<TEMPLATE_NAME_OR_ID>",
// optional: the automation template name
"recipient": "<RECIPIENT_ID>",
// optional: recipient id for the automation run
"data": {}
// optional: root level data to be passed into automation template
"profile": {}
// optional: root level profile information to be passed into your automation template
}

Examples

Batch Send to Multiple Recipients

Use the send action to send the messages to multiple recipients. Data for each message can vary per step. This includes data, profile, and the template.

// POST /automations/invoke
{
"automation": {
"steps": [
{
"action": "send",
"data": {},
"profile": {},
"recipient": "<RECIPIENT_ID_1>",
"template": "<TEMPLATE_ID_1>",
},
{
"action": "send",
"data": {},
"profile": {},
"recipient": "<RECIPIENT_ID_2>",
"template": "<TEMPLATE_ID_2>",
},
// ... more send events
]
}
}

Use Delay and Cancel Step

The delay step can be used to create delays between actions. The following is an example of an invite user flow that also includes a reminder. Because the user shouldn't be notified if they accept the invite, a cancelation token can be specified. This allows for a follow-up event to be called that can be used to cancel the original workflow.

// POST /automations/invoke
{
"automation": {
"cancelationToken": "<EVENT_NAME>/<USER_ID>", // invite-new-user/abc12345
"steps": [
{
"action": "send",
"template": "invite-user"
// data, profile, and recipient will be taken from the root level event
},
{
"action": "delay",
"duration": "1 day"
},
{
"action": "send",
"template": "invite-reminder"
// data, profile, and recipient will be taken from the root level event
}
]
}
}

// POST /automations/invoke (if invitation accepted before reminder sent)
{
"event": "<EVENT_NAME>",
"data": {},
"profile": {},
"user": "<USER_ID>",
"automation": {
"steps": [
{
"action": "cancel",
"cancelationToken": "invite-new-user/abc12345"
}
]
}
}

Send a notification template then invoke an automation template

{
"automation": {
"steps": [
{
"action": "send",
"template": "OUTREACH",
"recipient": "abc-123",
"profile": {
"email":"RECIPIENT EMAIL HERE"
},
},
{
"action": "invoke",
"template":"YOUR AUTOMATION TEMPLATE ID HERE"
}
]
}
}

Automation data logs

The automation logs provide detailed insights into the status of an automation run and step summaries. For more details, see: Using the automation data logs.

Did this answer your question?