Seven workflows. Workflow 1 is the gatekeeper: nothing else sends until it has cleared the contact. Every send also checks the channel's own window and the per-contact daily cap.
1. Cart Capture and Eligibility Gate
Trigger: cart-updated webhook from the store, with at least one line item and an identifiable contact (email or mobile captured at checkout, from an account login, or from a previous order).
Actions:
- Create or update the card at Cart Active. Write Cart ID, Cart Value, Cart Item Count, Cart Top Item Name, Cart Top Item Image URL, Cart Recovery URL, Cart Category.
- Wait 30 minutes. Condition: no further cart activity and no order? Move to Cart Abandoned, stamp Cart Abandoned At, apply cart-abandoned.
- Run the eligibility gate. Any failure moves the card to Suppressed and exits:
- : an order was placed in the last 30 minutes, for any items;
- : an open support or returns conversation exists on this contact;
- : sms-opted-out and email-unsubscribed are both present (if only one is, continue on the other channel);
- : Recovery Touch Count across all carts in the last 30 days is already 4 or more;
- : a recovery sequence ran for this contact inside the last 7 days;
- : three or more abandoned carts in 30 days → apply cart-serial-abandoner, restrict to email only, and allow a maximum of one touch.
- Segment: Lifetime Order Count 1 or more → cart-repeat-customer; zero → cart-first-timer. Cart Value above the high-value threshold → cart-high-value.
- Move to Recovery In Progress and hand to workflow 2.
Exit: gate failure, or any order placed.
2. Touch One: Email Reminder
Trigger: handed from workflow 1.
Actions:
- Wait 1 hour from Cart Abandoned At. Short enough that the intent is still warm, long enough not to look like surveillance.
- Condition: still no order, Recovery Touch Count under 3, not email-unsubscribed? If the email window has closed, hold until it opens.
- Branch: cart-first-timer: send the version that includes the returns window, the delivery promise and the payment methods accepted. A first-time buyer's hesitation is usually about trust, not price. Subject: “Your [Cart Top Item Name] is still in your basket”. Body opens: “No rush: we've kept it for you. Here's what you had, along with the bits people usually want to check before ordering: delivery takes [X] working days, returns are [Y] days, no questions asked.”
- Branch: cart-repeat-customer: shorter, warmer, no policy content. Subject: “Left something behind, [First Name]?” Body: “Your [Cart Top Item Name] is still saved. One tap and it's back in your basket.”
- Both versions: item images, the line-item list, shipping cost stated plainly rather than hidden until checkout, and exactly one call to action pointing at Cart Recovery URL. No discount.
- Reply-to is a monitored address, not no-reply. Set Recovery Touch Count = 1, Recovery Channel Last Used = Email.
Exit immediately on: order placed, any reply (hand to workflow 5), or email-unsubscribed.
3. Touch Two: SMS
Trigger: 1 hour after touch one sent, with no order.
Conditions, all required: Marketing Consent SMS is true, not sms-opted-out, not cart-serial-abandoner, Recovery Touch Count = 1, and a cell number exists. Any failure skips straight to workflow 4.
Actions:
- Wait until the next occurrence of 11:00am local time, inside the SMS window. Never send a recovery SMS at the same moment as the email, and never overnight. This single scheduling rule does more for opt-out rate than any copy change.
- Send one SMS, and only one: “[First Name]. Your [Cart Top Item Name] is still saved at [Store Name]. Finish up here: [Cart Recovery URL], or just reply if you have a question about delivery or sizing, a real person (or BO) will answer. Reply STOP to opt out.”
- The invitation to reply is deliberate. It converts a broadcast into a conversation and is where Abandonment Reason Given comes from.
- Set Recovery Touch Count = 2, Recovery Channel Last Used = SMS.
- Branch: cart-high-value: additionally create a task on the customer-service owner: Personal follow-up: high-value cart, [Cart Top Item Name], due in 4 business hours. A high-value cart justifies a human; a low-value one does not.
Exit immediately on: order placed, any reply, or sms-opted-out.
4. Touch Three: Obstacle Removal and Survey
Trigger: 48 hours after Cart Abandoned At with no order.
Conditions: Recovery Touch Count under 3, no reply received, channel consent intact.
Actions:
- Branch on the discount policy, decided before launch, not improvised here:
- : Discount permitted and cart-first-timer and Cart Value above the minimum: issue a unique, single-use, 72-hour code. Write Discount Code Issued and Discount Expires At, apply cart-discount-issued and Discount Offered. Email: “Still thinking about the [Cart Top Item Name]? Here's a code that takes a bit off, valid until [Discount Expires At]: [code]. After that it's gone. We only send these once.” The honesty about it being once-only is what stops the code becoming an expectation.
- : Discount not permitted, or cart-repeat-customer, or cart-discount-issued within 60 days: send the no-discount version, which removes an obstacle instead of cutting the price: free-shipping threshold and how close the cart is to it, stock position on the top item, the returns promise, and a prompt to ask a question. “Last note about the [Cart Top Item Name]. It's still in stock and still saved. If something's holding you up, tell me what it is and I'll sort it: [link]”
- Both versions include the One-Question Abandonment Survey link, framed as a favor rather than a form: “Not going to buy? That's completely fine. One click to tell us why genuinely helps: [link]”
- Set Recovery Touch Count = 3.
- Wait 24 hours. Condition: no order and no survey response? Move the card to Expired, apply cart-expired, remove cart-abandoned, and lock the contact out of cart recovery for 7 days.
Exit: order placed, reply received, or expiry.
5. Reply Handling and BO Conversation
Trigger: inbound reply on any channel from a contact carrying cart-abandoned, or a new web chat on the cart or checkout page.
Actions:
- Pause every scheduled step on this cart immediately. A sequence that keeps firing while the customer is mid-conversation is the most damaging failure mode in this entire build.
- Hand to BO with the shipping, delivery, returns, sizing and payment knowledge base, plus the live stock position on the cart items.
- BO classifies the message and writes Abandonment Reason Given from the eight options. Classification happens before the answer, so that even a conversation that goes nowhere leaves the reason behind.
- Branch: Shipping Cost: state the rate for their zone, the free-shipping threshold and the gap. Offer the qualifying-item route before any discount.
- Branch: Delivery Time: give the real window by method, and the cut-off for next-day if it exists.
- Branch: Out Of Stock: confirm the position, offer the Back-In-Stock Notify form, and suggest the nearest in-stock alternative in the same category.
- Branch: Payment Issue or Technical Problem: apply cart-escalated, create an urgent task, and notify a human. This is not a marketing problem, it is a broken checkout, and it is probably affecting other customers right now.
- Branch: Price or Still Comparing: BO answers on value, not price: materials, guarantee, what is included. It applies a discount code only if the pre-approved policy allows it at this touch, and never invents one.
- Branch: Changed Mind: BO thanks them, applies cart-recovery-suppressed, moves the card to Suppressed, and stops. Honouring a no is what makes the next sequence credible.
- Escalation: refund, return, damage, complaint, chargeback or fraud language, or two stalled turns → assign to a human with the full thread.
- On resolution with intent to buy, BO sends a fresh Cart Recovery URL (the original token may have expired) and resumes the ladder only if the remaining touch count allows and at least 24 hours have passed.
Exit: order placed, suppression applied, or human takeover.
6. Recovery Attribution and Sequence Teardown
Trigger: order-created webhook from the store.
Actions:
- Match the order to an open card on Cart ID first, then on contact identity with any line-item overlap, then on contact identity alone within the recovery window.
- Branch: matched to an open recovery card: move to Recovered, write Recovered Order ID and set Recovery Attributed Channel from Recovery Channel Last Used plus the link click, apply cart-recovered, remove cart-abandoned.
- Cancel every pending step across workflows 2, 3 and 4 for this contact. Test this path specifically; a recovery discount arriving after the customer paid full price is the single most expensive bug in a build like this.
- If Discount Code Issued exists and was not used on the order, void the code so it cannot be redeemed later.
- Branch: order with no matching cart: record it as organic, not recovered. Resisting the temptation to claim it is what makes the whole report believable.
- Apply cart-recovery-suppressed for 7 days, then clear it, so a next-day abandonment does not immediately re-sequence a fresh customer.
- Hand the contact to the post-purchase build and exit.
Exit: on completion.
7. Holdout Group, Reporting and Weekly Review
Trigger A: holdout assignment: on entry to Cart Abandoned.
- Assign a deterministic 5 percent of eligible carts to cart-holdout, hashed on Cart ID so the assignment is stable and reproducible.
- Holdout carts receive no recovery messaging at all and are tracked for organic purchase within 7 days.
- The difference between holdout and treated purchase rates is the real incremental recovery rate. Without it, you are reporting the behavior of people who were coming back anyway.
Trigger B: weekly report, Mondays 7am:
- Compile and send to the store owner and the marketing owner: carts abandoned, carts with a contactable identity, recovery rate against that denominator, recovered revenue gross and net of discounts and SMS cost, recovery rate by touch and by channel, holdout comparison, discount dependency, opt-out and unsubscribe rate on recovery sends specifically, and the Abandonment Reason Given distribution.
- Create a recurring task: Review abandonment reasons: action the top cause. The report is not the deliverable; the shipping-policy change or the checkout fix it prompts is.
Trigger C: guardrail alarms, daily 8am:
- If recovery-message opt-outs exceed the agreed threshold for two consecutive days, notify the owner and automatically reduce to email-only until reviewed. A build that can throttle itself is worth more than one that needs watching.
- If Abandonment Reason Given = Technical Problem or Payment Issue appears three or more times in 24 hours, alert immediately. That is an outage, not an abandonment pattern.
- If any contact receives more than two automated messages in a day from this build, log it as a cap breach and notify. Caps that are not monitored are not caps.
Exit: none; these run continuously.