How to create an abandoned checkout automation

Intro

Build an automation that re-engages shoppers who began checkout but did not complete a purchase. The workflow waits for inactivity, sends a reminder email, follows up with an SMS, and tags the contact for further segmentation.

See API reference: Automations | Event Metadata

Prerequisites

  • An API key with automations.write scope (add email-templates.write if creating a new template), or an OAuth token with the same scopes
  • Your store must already be sending the started checkout event — see How to enable cart/checkout abandonment for setup instructions
  • An email template prepared for the checkout reminder (see Email Templates API)

Block types used in this guide

This automation uses four block types:

Block typePurposeKey fields
delayPauses the workflow before the next block executes. Mode can be duration (wait N time units), immediate (no wait), or specificTime (wait until a clock time).mode, duration.amount, duration.units
action → sendEmailSends an email using a pre-built template. The template content is copied into the automation at creation time.templateID (required), subject, senderName, preheader, language
action → sendSmsSends an SMS (or MMS in US/CA with an image). Requires a message body and compliance settings for opt-out text.message, compliance
action → addTagAdds a tag to the contact for segmentation or downstream logic. Tags are case-insensitive.value (the tag string)

Step 1: Look up the trigger event metadata

Before building the automation, verify that the started checkout event is available for your brand and identify the correct origin value. The Event Metadata API returns event names, origins, and property paths your brand can use.

See endpoint: Query events metadata

curl -X POST 'https://api.omnisend.com/api/event-metadata' \
  -H 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
  -H 'Omnisend-Version: 2026-03-15' \
  -H 'Content-Type: application/json' \
  -d '{
    "category": "automations",
    "events": ["started checkout"],
    "includeProperties": true
  }'

The response lists each origin that provides this event for your brand (e.g. shopify, api, woocommerce) and the property paths you can use in trigger filters. Use the origins array from the response to set the correct origin in Step 2.

Note: If the response is empty, your store is not sending started checkout events yet. Follow the cart/checkout abandonment setup guide first.

Step 2: Create the automation

Create the abandoned checkout automation with a trigger, exit condition, inactivity timer, and the full block sequence: email → delay → SMS → tag.

The inactivitySettings ensures the workflow only fires after the shopper has been idle for 1 hour — any new checkout activity resets the timer, so the email reflects their final cart.

See endpoint: Create automation workflow

curl -X POST 'https://api.omnisend.com/api/automations' \
  -H 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
  -H 'Omnisend-Version: 2026-03-15' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Abandoned Checkout Recovery",
    "trigger": {
      "condition": {
        "event": "started checkout",
        "origin": "api"
      },
      "inactivitySettings": {
        "duration": { "amount": 1, "units": "h" }
      }
    },
    "exitConditions": [
      {
        "event": "placed order",
        "origin": "api"
      }
    ],
    "blocks": [
      {
        "temporaryID": "email-reminder",
        "type": "action",
        "action": {
          "type": "sendEmail",
          "sendEmail": {
            "templateID": "000000000000000000000001",
            "subject": "You left something behind!",
            "senderName": "My Store",
            "preheader": "Complete your order before items sell out",
            "language": "en_US"
          }
        }
      },
      {
        "temporaryID": "wait-24h",
        "type": "delay",
        "delay": {
          "mode": "duration",
          "duration": { "amount": 24, "units": "h" }
        }
      },
      {
        "temporaryID": "sms-followup",
        "type": "action",
        "action": {
          "type": "sendSms",
          "sendSms": {
            "message": "Hi [[contact.first_name]], your cart is still waiting! Complete your checkout: [[checkout_url]]",
            "compliance": {
              "isStopKeywordIncluded": true,
              "stopKeywordText": "Reply STOP to opt out",
              "isUnsubscribeLinkIncluded": true,
              "unsubscribeLinkText": "Unsubscribe [[unsubscribe_link]]"
            }
          }
        }
      },
      {
        "temporaryID": "tag-reached-sms",
        "type": "action",
        "action": {
          "type": "addTag",
          "addTag": {
            "value": "reached_abandonment_sms"
          }
        }
      }
    ]
  }'

The response returns the automation in disabled state with a server-assigned id. Save this ID for the enable step.

Note: Replace "origin": "api" with the origin returned by the Event Metadata endpoint in Step 1 (e.g. "shopify", "woocommerce"). The origin must match both the trigger and the exit condition.

Note: exitConditions uses OR logic — the contact exits immediately when any listed event fires. Here, a single placed order event removes the contact so they do not receive further reminders after purchasing.

Step 3: Enable the automation

Activate the automation so it starts processing trigger events.

See endpoint: Enable automation workflow

curl -X POST 'https://api.omnisend.com/api/automations/AUTOMATION_ID/enable' \
  -H 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
  -H 'Omnisend-Version: 2026-03-15' \
  -H 'Content-Type: application/json' \
  -d '{
    "enrollExisting": false
  }'

A 200 response confirms the automation is now enabled. The isEnabled field is true and enabledAt shows the activation timestamp.

Note: The enrollExisting option retroactively enrolls contacts whose trigger event occurred within the first delay block's time window. It requires a delay block as the very first step in the workflow. The automation above starts with an action (email), so enrollExisting: true is rejected with 409. To use it, insert a delay block before the email — its duration defines how far back the engine looks for qualifying events.

Verify results

Retrieve the automation to confirm it is enabled and all blocks are in place.

See endpoint: Get automation workflow

curl -X GET 'https://api.omnisend.com/api/automations/AUTOMATION_ID' \
  -H 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
  -H 'Omnisend-Version: 2026-03-15'

Check that isEnabled is true and blocks contains the four blocks you defined. Each block now has a server-assigned id replacing the temporaryID you provided.

Troubleshooting

  • 409 Conflict on enable with enrollExisting: The automation must start with a delay block as its first step. Add a delay block before the first action — its duration defines the enrollment window for past events.
  • 400 on create — origin mismatch: The origin in trigger.condition and exitConditions must be an origin your brand has event data for. Use the Event Metadata endpoint to check available origins.
  • 409 Conflict on PATCH while enabled: The automation is currently enabled. Disable it first via POST /automations/{id}/disable, make changes, then re-enable.
  • SMS not delivered: Contacts must be SMS-subscribed. The default sendingThresholds is subscribed — non-subscribers are skipped (controlled by isSkipAllowed on the block).

Related resources