Automations

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 typeDescription
delayPause the workflow before continuing to the next block
actionExecute an operation (send a message, manage tags)
splitBranch contacts based on event, contact, or message engagement conditions
abTestingRandomly split contacts between two variant paths by percentage

Action types

TypeDescription
sendEmailSend an email using a template (Email Templates API)
sendSmsSend an SMS or MMS message
sendPushSend a web push notification
sendWebhookSend an HTTP POST to an external URL
addTagAdd a tag to the contact
removeTagRemove a tag from the contact

Email, SMS, and push blocks have an isSkipAllowed flag. When true, contacts who are ineligible to receive the channel's message skip the block and continue. When false, they exit the workflow. This flag does not apply to webhooks. Email and SMS default to true.

Push blocks: For sendPush, omitting isSkipAllowed when creating an automation (POST) or replacing its blocks (PUT) defaults to false. Set "isSkipAllowed": true explicitly to let an ineligible contact skip the push block and continue. Omitting this field in a PATCH leaves its saved value unchanged.

Action configuration is nested under its matching type, such as action.sendPush for "type": "sendPush".

Delay modes

ModeDescription
durationWait for a specified amount of time (duration.amount + duration.units: m/h/d/w/M)
immediateNo wait — proceed to the next block immediately
specificTimeWait 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.

A delay cannot be the last block in the workflow. A branch may end with a delay only when a shared downstream sequence follows the split or A/B test.

Split filters

A split evaluates a filterGroup of mixed-type filters:

Filter typefieldoperator examplesvalue
eventEvent property patheq, neq, gt, contains, exists, in, …Property value
contactContact attribute (tag, country, segmentID, …)Same set as audience contact filtersAttribute value
messageAlways "blockID"openedEmail, clickedEmail, clickedSms, openedPush, clickedPushID of a send block above this split

Set filterGroup.logicalOperator to and or or. Event filters use the triggering event's properties; contact filters check current contact attributes.

Clicked message filters may include urlMatch with an operator of any, is, contains, startsWith, or endsWith. Supply a URL value unless the operator is any. Omit urlMatch for opened-message, event, and contact filters.

Note: Sibling blocks placed after a split run for contacts from both branches — the branches reconverge on that shared downstream sequence. Branches may contain different numbers of blocks, and a branch may end with a delay when such a shared continuation exists.

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.

Use the event metadata endpoint to look up event names, origins, and property paths available for the brand. When an event has multiple origins, specify one; a single origin is selected automatically. Omit origin for "subscribed to marketing".

To enroll contacts when they enter a segment, use "event": "entered segment", "origin": "omnisend", and a trigger event filter on segment_id. A contact audience filter on segmentID only checks membership after a trigger fires.

Optional trigger.condition.filterGroups narrow enrollment by event properties:

  • Most events accept at most one filter group.
  • "subscribed to marketing" accepts up to 10 groups, combined with AND logic.
  • "product back in stock" does not accept filter groups. This trigger is supported for Shopify, BigCommerce, and WooCommerce stores.
  • "birthday" has a special filter format; see the trigger condition examples.

Event filter values

Within an event filter group, set logicalOperator to and or or. Available comparison operators depend on the event property's type. Numeric comparisons (gt, gte, lt, lte) require numeric properties and JSON numbers: use "value": 50, not "value": "50". String properties require string values.

Omit value for exists and notExists. For string-list properties, in and notIn test membership using a single string value, not an array. These rules also apply to event filters in splits and exit conditions.

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. Set logicalOperator to and or or and supply at least one filter.

All contact filter values are non-empty strings. The same field and operator rules apply to contact filters in split blocks:

FieldOperatorsValue
segmentIDeq, neqSegment ID
tageq, neqTag name
dateAddedeq, neq, gt, ltDate in YYYY-MM-DD format
firstName, lastName, state, city, postalCodeeq, neq, contains, notContainsAttribute value
countryeq, neq, contains, notContainsISO-2 country code, such as US
gendereqm or f

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.

Use a positive amount and units m, h, d, or w.

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.

LevelDescription
subscribedOnly contacts who opted in to marketing (default)
nonSubscribedSubscribed + non-subscribed, excluding those who explicitly unsubscribed
allAll 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 sms threshold (CTIA regulation).

Frequency limiter

Restricts how often the same contact can re-enter the automation.

ModeDescription
onceContact enters the automation only once per lifetime
intervalContact can re-enter after a specified duration since last entry

For interval, supply a positive duration.amount with units h, d, or w (maximum 8760 hours, 365 days, or 52 weeks). Omit duration for once. 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.

ModeDescription
currentlyInSkip if the contact is currently active in any listed automation
recentlyInSkip if the contact completed any listed automation within withinDays days (1–7)

Supply a non-empty automationIDs list. withinDays is required for recentlyIn and must be omitted for currentlyIn. Send null to clear the limiter.

Note: Self-referencing (listing the automation's own ID in automationIDs) is rejected with 400.

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", and custom virtual events: not supported with enrollExisting=true; the API returns 409 enroll-existing-not-applicable.

When enrollExisting is omitted or false, only future trigger events are processed. Re-enabling a segment-triggered workflow with enrollExisting=true returns 409 enroll-existing-not-applicable.

Disable (POST /automations/{id}/disable): stops accepting new trigger events. contactsInWorkflow controls in-flight contacts:

ValueDescription
keepContacts remain and continue through remaining blocks
exitAll contacts are immediately removed from the workflow

Other Lifecycle Actions

ActionEndpointDescription
CopyPOST /automations/{id}/copyCreate a disabled copy. Optional name field; defaults to "Copy of: <original name>"

Editing Automations

Use PATCH /automations/{id} to update a disabled automation. Omitted fields remain unchanged:

FieldUpdate behavior
triggerUpdate only the supplied sub-fields. Each supplied condition, audienceFilterGroup, or inactivitySettings replaces that sub-field in full.
exitConditionsReplace the entire list. Send null or [] to clear it.
blocksUpdate existing blocks by id; do not add, remove, or reorder blocks. An empty array is rejected.
settingsUpdate only the supplied sub-fields.

For a block PATCH, delay is replaced in full, including its mode-specific fields. split.filterGroup is also replaced in full; split branches cannot be changed through PATCH. For A/B tests, only aBlocksPercentage can be patched.

Use PUT /automations/{id}/blocks to replace the complete block tree, including branch structure:

  • Identify existing blocks with id and new blocks with a unique temporaryID.
  • Existing blocks omitted from the replacement tree are removed.
  • Existing block and action types cannot be changed in place; use a new block to change types.
  • For new email blocks, templateID is required. For existing email blocks, omit templateID; it must not be provided.

Test Emails

Use POST /automations/{id}/blocks/{blockID}/test-email to send a test of an email block's saved content. Supply 1–5 valid email addresses:

{
  "recipients": ["[email protected]"]
}

A 204 No Content response means the request was accepted for asynchronous delivery. The block must be an email block with saved content. Sending can be rejected if all recipients are suppressed, email sending is disabled, the sender domain is unverified, or the billing plan does not allow sending.

UTM Tracking

UTM tags can be managed per email, SMS, or push block or read in aggregate. Webhook and tag actions do not support UTM tags.

EndpointDescription
GET /automations/{id}/blocks/{blockID}/utmRead UTM tags for a single block
PUT /automations/{id}/blocks/{blockID}/utmSet UTM tags for a single block
GET /automations/{id}/utmRead aggregated UTM tags for all email, SMS, and push 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:

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"
  }
}'

See Also