Intro
Endpoint: https://api.omnisend.com/api/automations
Build event-driven workflows that send messages, apply tags, and branch logic based on contact behavior. Automations are created disabled and must be explicitly enabled to start processing trigger events.
Blocks
Workflows are composed of ordered blocks. Each block has a type discriminator and exactly one type-specific field populated.
| Block type | Description |
|---|---|
| delay | Pause the workflow before continuing to the next block |
| action | Execute an operation (send a message, manage tags) |
| split | Branch contacts based on event, contact, or message engagement conditions |
| abTesting | Randomly split contacts between two variant paths by percentage |
Action types
| Type | Description |
|---|---|
| sendEmail | Send an email using a template (Email Templates API) |
| sendSms | Send an SMS or MMS message |
| sendPush | Send a web push notification |
| sendWebhook | Send an HTTP POST to an external URL |
| addTag | Add a tag to the contact |
| removeTag | Remove a tag from the contact |
Each send-action block has an isSkipAllowed flag (default true). When true, ineligible contacts skip the block and continue. When false, the workflow is canceled for that contact.
Delay modes
| Mode | Description |
|---|---|
| duration | Wait for a specified amount of time (duration.amount + duration.units: m/h/d/w/M) |
| immediate | No wait — proceed to the next block immediately |
| specificTime | Wait until a time of day in the brand's timezone (time in HH:MM 24h format) |
All delay modes support optional allowedWeekdays to restrict resolution to specific days.
Split filters
A split evaluates a filterGroup of mixed-type filters:
| Filter type | field | operator examples | value |
|---|---|---|---|
| event | Event property path | eq, neq, gt, contains, exists, in, … | Property value |
| contact | Contact attribute (tag, country, segmentID, …) | Same set as audience contact filters | Attribute value |
| message | Always "blockID" | openedEmail, clickedEmail, clickedSms, openedPush, clickedPush | ID of a send block above this split |
Note: A split owns its continuation through
trueBlocksandfalseBlocks. Do not place sibling blocks after a split — move downstream blocks into each branch.
Triggers
trigger.condition.event specifies the event that enrolls contacts. Most events use standard Events API names (e.g. "placed order", "started checkout") and may require origin. Built-in events ("birthday", "product back in stock") do not use origin.
Optional trigger.condition.filterGroups narrow enrollment by event properties. Multiple filter groups combine with AND logic.
Audience filter group
trigger.audienceFilterGroup restricts which contacts enter the workflow when the trigger fires. It does not trigger the automation — it only gates enrollment. Supported fields: segmentID, tag, dateAdded, firstName, lastName, gender, country, state, city, postalCode.
Inactivity settings
trigger.inactivitySettings.duration delays the workflow start until the contact has been inactive (no new triggering events) for the specified period. Each re-trigger resets the timer.
Note: Use inactivity settings for abandoned-flow patterns — e.g. 30 min after
"added product to cart"with no follow-up cart event.
Exit Conditions
exitConditions remove contacts from the automation when a matching event occurs. Multiple exit conditions are evaluated with OR logic. Each condition specifies an event (and optional origin and filterGroup).
Note: Built-in trigger events (
"birthday","product back in stock") cannot be used as exit conditions.
Settings
Sending thresholds
Control which contacts receive messages at send blocks based on subscription status.
| Level | Description |
|---|---|
| subscribed | Only contacts who opted in to marketing (default) |
| nonSubscribed | Subscribed + non-subscribed, excluding those who explicitly unsubscribed |
| all | All contacts regardless of subscription status (transactional use) |
Set per channel (email, sms). Push is always restricted to subscribed contacts.
Note: US SMS is always restricted to subscribed contacts regardless of the
smsthreshold (CTIA regulation).
Frequency limiter
Restricts how often the same contact can re-enter the automation.
| Mode | Description |
|---|---|
| once | Contact enters the automation only once per lifetime |
| interval | Contact can re-enter after a specified duration since last entry |
Send null to clear an existing limiter.
Overlap limiter
Prevents a contact from entering when they are already in (or recently completed) other specified automations.
| Mode | Description |
|---|---|
| currentlyIn | Skip if the contact is currently active in any listed automation |
| recentlyIn | Skip if the contact completed any listed automation within withinDays days (1–7) |
Note: Self-referencing (listing the automation's own ID in
automationIDs) is rejected with400.
Lifecycle: Enable / Disable
Automations are always created disabled. The isEnabled field is read-only — use the dedicated enable/disable endpoints to change state.
Warning: Enabled automations cannot be patched or have blocks replaced — the API returns
409 Conflict. Disable the automation first, make changes, then re-enable.
Enable (POST /automations/{id}/enable): starts processing trigger events. enrollExisting optionally enrolls contacts who already qualify:
- Event-based triggers: contacts whose event occurred within the first delay block's time window are enrolled. The workflow must start with a delay block — otherwise
409 enroll-existing-not-applicable. "entered segment"trigger: all contacts currently in the trigger segments are enrolled. Only works on the first enable."birthday","product back in stock": not supported withenrollExisting.
Disable (POST /automations/{id}/disable): stops accepting new trigger events. contactsInWorkflow controls in-flight contacts:
| Value | Description |
|---|---|
| keep | Contacts remain and continue through remaining blocks |
| exit | All contacts are immediately removed from the workflow |
Other Lifecycle Actions
| Action | Endpoint | Description |
|---|---|---|
| Copy | POST /automations/{id}/copy | Create a disabled copy. Optional name field; defaults to "Copy of: <original name>" |
UTM Tracking
UTM tags can be managed per send-action block or read in aggregate.
| Endpoint | Description |
|---|---|
GET /automations/{id}/blocks/{blockID}/utm | Read UTM tags for a single block |
PUT /automations/{id}/blocks/{blockID}/utm | Set UTM tags for a single block |
GET /automations/{id}/utm | Read aggregated UTM tags for all send-action blocks |
All three tag fields (source, medium, campaign) are replaced atomically on write. Send an empty string to clear a field — the next read returns its default value.
For a complete walkthrough, see How to configure UTM tags for automations.
Examples
For trigger condition and audience filter group examples, see the endpoint documentation:
- Create automation: Trigger condition examples — birthday, entered segment, event-based triggers with filter groups
- Create automation: Audience filter group examples — segment, tag, location, and date-based audience filters
- Patch automation: Audience filter group examples — replace or narrow audience filters on existing automations
Example: Create an automation with a welcome email
curl --request POST \
--url https://api.omnisend.com/api/automations \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"name": "Welcome Series",
"trigger": {
"condition": {
"event": "subscribed to marketing"
}
},
"blocks": [
{
"temporaryID": "wait-1h",
"type": "delay",
"delay": {
"mode": "duration",
"duration": {
"amount": 1,
"units": "h"
}
}
},
{
"temporaryID": "welcome-email",
"type": "action",
"action": {
"type": "sendEmail",
"sendEmail": {
"subject": "Welcome to our store!",
"senderName": "My Store",
"preheader": "Thanks for subscribing",
"language": "en_US",
"templateID": "000000000000000000000001"
}
}
}
]
}'Creates a disabled automation that triggers on marketing subscription, waits 1 hour, then sends a welcome email.
Example: Enable an automation
curl --request POST \
--url https://api.omnisend.com/api/automations/000000000000000000000001/enable \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"enrollExisting": false
}'Example: Disable an automation
curl --request POST \
--url https://api.omnisend.com/api/automations/000000000000000000000001/disable \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"contactsInWorkflow": "keep"
}'Example: Replace automation blocks
curl --request PUT \
--url https://api.omnisend.com/api/automations/000000000000000000000001/blocks \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"blocks": [
{
"temporaryID": "wait-30m",
"type": "delay",
"delay": {
"mode": "duration",
"duration": {
"amount": 30,
"units": "m"
}
}
},
{
"temporaryID": "tag-engaged",
"type": "action",
"action": {
"type": "addTag",
"addTag": {
"value": "engaged"
}
}
}
]
}'Replaces the entire block tree. Blocks with temporaryID are created as new; blocks with id update existing ones. Existing blocks not included are removed.
Note: The automation must be disabled before replacing blocks.
Example: Update UTM tags for a block
curl --request PUT \
--url https://api.omnisend.com/api/automations/000000000000000000000001/blocks/000000000000000000000002/utm \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"tags": {
"source": "omnisend",
"medium": "email",
"campaign": "welcome-series"
}
}'