{
  "id": "FpauF9jfmoRaFe8q",
  "name": "Abandoned Cart Recovery Engine",
  "tags": [],
  "nodes": [
    {
      "id": "51574280-e48b-4296-99a7-6e1ef44a1999",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        -240
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 1144,
        "content": "## \ud83d\uded2 Abandoned Cart Recovery Engine\n\nDetects Shopify checkouts abandoned in real time, waits 15 minutes to confirm non-completion, then sends a personalized multi-channel recovery sequence via email and WhatsApp with a time-limited discount code.\n\n**Perfect for:** ecommerce teams managing cart abandonment and customer retention.\n\n---\n\n## How it works\n\n1. **Checkout Abandoned** \u2014 Shopify trigger fires when a checkout is created.\n2. **Wait 15 Min** \u2014 Pauses execution to allow customer time to complete manually.\n3. **Check Order Status** \u2014 HTTP request queries Shopify for orders matching the checkout token.\n4. **Order Completed?** \u2014 If condition: branches on whether an order exists.\n5. **Cart Converted** \u2014 No-op endpoint if order already completed (ends flow).\n6. **Build Recovery Message** \u2014 Set node extracts customer email, phone, cart items, and constructs recovery variables.\n7. **Send Recovery Email** \u2014 Gmail node sends personalized HTML email with discount code and checkout link.\n8. **Send Recovery WhatsApp** \u2014 WhatsApp node sends compact SMS-style message to customer phone.\n9. **Error Trigger** \u2014 Error handler catches any workflow failure.\n10. **Notify Ops** \u2014 Slack node alerts ops team if error occurs.\n\n---\n\n## Setup (about 15 minutes)\n\n1. **Shopify Admin API** \u2014 Connect your credential in *Checkout Abandoned*. Topic must be `checkouts/create`.\n2. **Shopify Admin Header Auth** \u2014 Add header auth credentials in *Check Order Status* pointing to `/admin/api/2024-01/orders.json`.\n3. **Gmail Account** \u2014 Connect Gmail OAuth in *Send Recovery Email*. Customize subject and HTML body if needed.\n4. **WhatsApp Business Account** \u2014 Connect and set `phoneNumberId` in *Send Recovery WhatsApp*.\n5. **Slack Account** \u2014 Connect Slack OAuth in *Notify Ops* and select your ops-alerts channel.\n> Adjust the wait time in *Wait 15 Min* from 15 minutes to match your recovery aggressiveness. Discount code is hardcoded in *Build Recovery Message* as `COMEBACK10` \u2014 update it to your active code."
      },
      "typeVersion": 1
    },
    {
      "id": "c2f61d8f-b18e-4c8c-8ead-4be4fe4a001c",
      "name": "1\ufe0f\u20e3 Trigger & Detect",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -96
      ],
      "parameters": {
        "color": 5,
        "width": 420,
        "height": 496,
        "content": "## 1\ufe0f\u20e3 Trigger & Detect\n\nThe **Checkout Abandoned** trigger watches Shopify for abandoned checkouts in real time. The **Wait 15 Min** node pauses before proceeding, giving customers a final window to complete their purchase manually without prompting."
      },
      "typeVersion": 1
    },
    {
      "id": "c8664e30-6069-4070-92a7-57e5080a7fba",
      "name": "2\ufe0f\u20e3 Verify & Decide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        -64
      ],
      "parameters": {
        "color": 3,
        "width": 420,
        "height": 416,
        "content": "## 2\ufe0f\u20e3 Verify & Decide\n\nThe **Check Order Status** node queries Shopify to confirm the cart is still abandoned. The **Order Completed?** condition branches: if an order exists, the **Cart Converted** endpoint stops the flow. Otherwise, recovery continues."
      },
      "typeVersion": 1
    },
    {
      "id": "15330b06-e8c1-4260-8683-c98d11807f9a",
      "name": "3\ufe0f\u20e3 Build & Send",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1072,
        -176
      ],
      "parameters": {
        "color": 6,
        "width": 420,
        "height": 812,
        "content": "## 3\ufe0f\u20e3 Build & Send\n\nThe **Build Recovery Message** node extracts customer contact info and cart contents into recovery variables. The **Send Recovery Email** and **Send Recovery WhatsApp** nodes fire in parallel, delivering personalized messages with the discount code and checkout link to both channels."
      },
      "typeVersion": 1
    },
    {
      "id": "5ee042aa-f50b-4803-80bc-aed762791d43",
      "name": "4\ufe0f\u20e3 Monitor",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        416
      ],
      "parameters": {
        "color": 4,
        "width": 420,
        "height": 388,
        "content": "## 4\ufe0f\u20e3 Monitor\n\nThe **Error Trigger** catches any workflow failure. The **Notify Ops** node immediately alerts the ops team via Slack with error details and workflow name for rapid troubleshooting."
      },
      "typeVersion": 1
    },
    {
      "id": "92919a2b-09cd-495b-85ab-ee2297d2d335",
      "name": "Checkout Abandoned",
      "type": "n8n-nodes-base.shopifyTrigger",
      "position": [
        160,
        176
      ],
      "parameters": {
        "topic": "checkouts/create"
      },
      "typeVersion": 1
    },
    {
      "id": "7ecb7715-84cf-4864-8104-4cdb73571c20",
      "name": "Wait 15 Min",
      "type": "n8n-nodes-base.wait",
      "position": [
        400,
        176
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "2ae6793b-8f72-47bd-87b6-aab2c2fbff46",
      "name": "Check Order Status",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 3,
      "position": [
        640,
        176
      ],
      "parameters": {
        "url": "=https://{{ $json.body.domain || \"YOUR_STORE\" }}.myshopify.com/admin/api/2024-01/orders.json",
        "options": {
          "timeout": 10000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "checkout_token",
              "value": "={{ $json.body.token }}"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "waitBetweenTries": 2000
    },
    {
      "id": "2fb60fe1-dc86-4ed6-9aa7-b3ebb2d53e5b",
      "name": "Order Completed?",
      "type": "n8n-nodes-base.if",
      "position": [
        880,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-order-completed",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ ($json.orders || []).length }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "82a94e33-4fb3-4a41-be59-cec2e864beab",
      "name": "Cart Converted",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1120,
        64
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d8a02a2e-70ab-4db8-98fb-f789f94b4e0a",
      "name": "Build Recovery Message",
      "type": "n8n-nodes-base.set",
      "position": [
        1120,
        304
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "customerEmail",
              "type": "string",
              "value": "={{ $('Checkout Abandoned').item.json.body.email }}"
            },
            {
              "id": "a2",
              "name": "customerPhone",
              "type": "string",
              "value": "={{ $('Checkout Abandoned').item.json.body.phone }}"
            },
            {
              "id": "a3",
              "name": "cartSummary",
              "type": "string",
              "value": "={{ ($('Checkout Abandoned').item.json.body.line_items || []).map(i => i.title + ' x' + i.quantity).join(', ') }}"
            },
            {
              "id": "a4",
              "name": "discountCode",
              "type": "string",
              "value": "COMEBACK10"
            },
            {
              "id": "a5",
              "name": "recoveryUrl",
              "type": "string",
              "value": "={{ $('Checkout Abandoned').item.json.body.abandoned_checkout_url }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5b3667b4-d776-4d28-8f82-b28232feeea4",
      "name": "Send Recovery Email",
      "type": "n8n-nodes-base.gmail",
      "maxTries": 2,
      "position": [
        1360,
        224
      ],
      "parameters": {
        "sendTo": "={{ $json.customerEmail }}",
        "message": "=<p>Still thinking it over? Here's 10% off to finish checking out: <b>{{ $json.discountCode }}</b></p><p>{{ $json.cartSummary }}</p><p><a href=\"{{ $json.recoveryUrl }}\">Complete your order</a></p>",
        "options": {
          "appendAttribution": false
        },
        "subject": "You left something in your cart \ud83d\udc40"
      },
      "retryOnFail": true,
      "typeVersion": 2.1
    },
    {
      "id": "40b0252b-b9d1-4431-b51a-34fd9bfa73da",
      "name": "Send Recovery WhatsApp",
      "type": "n8n-nodes-base.whatsApp",
      "maxTries": 2,
      "position": [
        1360,
        384
      ],
      "parameters": {
        "textBody": "=Hey! You left {{ $json.cartSummary }} in your cart. Use code {{ $json.discountCode }} for 10% off: {{ $json.recoveryUrl }}",
        "operation": "send",
        "phoneNumberId": "REPLACE_WITH_PHONE_NUMBER_ID",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $json.customerPhone }}"
      },
      "retryOnFail": true,
      "typeVersion": 1.1,
      "continueOnFail": true
    },
    {
      "id": "0d94b82f-f1ca-44f2-a375-076a44a5bb91",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        160,
        608
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "4371a190-103c-4d3c-a98e-e9678404a60f",
      "name": "Notify Ops",
      "type": "n8n-nodes-base.slack",
      "position": [
        400,
        608
      ],
      "parameters": {
        "text": "=\ud83d\udea8 Abandoned Cart Recovery Engine failed: {{ $json.execution.error.message }} (workflow: {{ $json.workflow.name }})",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_CHANNEL_ID",
          "cachedResultName": "ops-alerts"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "1adc511f-bae1-45df-952d-4f07e3aab848",
  "nodeGroups": [],
  "connections": {
    "Wait 15 Min": {
      "main": [
        [
          {
            "node": "Check Order Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Notify Ops",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Order Completed?": {
      "main": [
        [
          {
            "node": "Cart Converted",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Recovery Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Order Status": {
      "main": [
        [
          {
            "node": "Order Completed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Checkout Abandoned": {
      "main": [
        [
          {
            "node": "Wait 15 Min",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Recovery Message": {
      "main": [
        [
          {
            "node": "Send Recovery Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Recovery WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}