Skip to content

Post-Purchase Follow-Up Automation in AcelleMail — Thank, Review, Cross-Sell

A confirmation email is just the start. Layer in a delivery-day check-in, a 7-day review request, a 30-day cross-sell, a 60-day "we miss you". This guide builds the full post-purchase flow in AcelleMail's automation builder using tags or custom events fired from your ecommerce backend.

What "post-purchase" actually means

A post-purchase flow is a sequence of emails that fires AFTER someone buys — automatically, without you scheduling each send. The right flow varies by what you sell, but every successful one shares the same skeleton:

Stage Timing Goal
Confirmation Immediately Reassure: order received, here's what happens next
Shipping notification When tracking is available Set expectation for arrival
Delivery check-in 1-2 days after delivery Confirm satisfaction, surface issues early
Review request 7 days after delivery Capture social proof while memory is fresh
Cross-sell / replenishment 30 days after purchase Right-time the next-purchase nudge
Win-back 60-90 days if no return purchase Re-engage before they forget

AcelleMail's automation builder handles all of this with three trigger types: Tag added, Custom event, and Date relative (post-tag).

Setup: two paths depending on your ecommerce stack

Path A: Tag-driven (simpler, manual or webhook-pushed)

When a purchase happens, your ecommerce system tags the subscriber in AcelleMail with a tag like purchased-2026-05-19 or just recent-purchaser. The automation triggers on tag add.

Path B: Custom-event-driven (richer, more flexible)

Your ecommerce system fires a custom event with payload like {"event": "purchase_completed", "order_total": 87.50, "products": ["sku-001", "sku-007"]}. The automation triggers on the event + uses payload data in subsequent steps.

For most senders Path A is enough to start. Switch to Path B when you need conditional flows ("if order over $100 → premium review request track; else standard track").

Build the flow (Path A — tag-driven)

Open the visual automation builder

In AcelleMail's left sidebar, click AutomationAutomations. The index lists every automation in this account with its current state:

Automations index

Click New automation in the top-right toolbar. The trigger picker opens:

Trigger picker — pick what starts the automation

For the confirmation email step:

  1. Trigger: Tag added
  2. Tag: recent-purchaser
  3. Action: send the Confirmation email immediately

Drop in the email step, write your confirmation copy. Save. The trigger now fires the email whenever recent-purchaser tag is added to anyone.

Add downstream steps inside the same automation:

[Trigger: tag added 'recent-purchaser']
  →
[Email: Order Confirmation]
  Wait: 3 days
[Email: How's it going? (delivery check-in)]
  Wait: 4 days  (=7 days from purchase)
[Email: Leave a review]
  Wait: 23 days  (=30 days from purchase)
[Email: You might also like...]
  Wait: 30 days  (=60 days from purchase)
[Condition: did NOT purchase again]
  →
[Email: We miss you — here's 10% off]

The visual builder:

Multi-step automation flow

Each "Wait" step is delay-based — AcelleMail queues the next step's send time per-subscriber individually.

Tag-source patterns

The tag recent-purchaser arrives in AcelleMail one of three ways:

Webhook from ecommerce platform

Shopify / WooCommerce / Magento / BigCommerce all send order webhooks. Configure a bridge service (Cloudflare Worker, Zapier, n8n, custom backend) to translate the webhook into an AcelleMail API call:

[Shopify webhook: order/created]
  → bridge service receives
  → POST to https://acellemail.com/api/v1/subscribers/{uid}/tags
    body: { "tags": ["recent-purchaser"] }

The subscriber must already exist in your AcelleMail list (or use the upsert API to create-if-not-exists).

Manual tag-add from the subscriber detail view

For small senders, the easiest path is manual: open the subscriber, Tags section, click Add tagrecent-purchaser:

Subscriber tags UI

Workable for low-volume; not scalable.

CSV import / bulk re-tag

Export today's orders → CSV with email + tags columns → import into AcelleMail via Audience → [list] → Import with the duplicate-handling set to Update. Existing subscribers get the new tag, the automation fires.

Common UI signals + fixes

Symptom Likely cause UI fix
Confirmation email doesn't send when order placed Webhook from ecommerce isn't reaching AcelleMail Test the webhook destination URL directly with curl; verify auth header
Subscriber gets confirmation but no follow-ups Wait step not advancing Open automation → check run-log for blocked subscribers (waiting on Wait timer; OR exited automation due to unsubscribe)
Same subscriber gets 3 confirmation emails Tag added 3 times (re-imported 3 times) Switch to "Tag changed to" not "Tag added" — fires only once per state change
Review request fires before delivery "7 days from tag add" but tag was added at order time, before shipping Have ecommerce add a separate "order-delivered" tag when tracking shows delivered; trigger review on that tag instead
Cross-sell email recommends item already purchased Email body hard-codes product list, ignores purchase history Use merge tags from custom fields populated at purchase time, OR fall back to popular-items

Path B — Custom event triggers

Switch to events when the flow needs to react to what was purchased, not just that a purchase happened.

Fire the event from your ecommerce backend:

curl -X POST "https://acellemail.com/api/v1/events" \
  -H "Authorization: Bearer $ACELLE_TOKEN" \
  -d '{
    "subscriber_email": "[email protected]",
    "event": "purchase_completed",
    "data": {
      "order_total": 87.50,
      "currency": "USD",
      "products": ["yoga-mat-blue", "yoga-block-pair"],
      "category": "fitness"
    }
  }'

In AcelleMail, build the automation:

  1. Trigger: Custom event, event name = purchase_completed
  2. Conditional step: branch on data.order_total > 100
  3. Branch A (high-value): premium review request track
  4. Branch B (standard): standard review request track

Custom-event triggers let the automation read the event's payload — {{ event.data.order_total }} works in email body, {{ event.data.products[0] }} for the product name in subject, etc.

Advanced: ecommerce webhook setups for Shopify, WooCommerce, Stripe

The bridge between your store and AcelleMail is where most "post-purchase doesn't fire" bugs hide. Here are concrete patterns for the three most common platforms.

Shopify → AcelleMail:

# 1. In Shopify admin: Settings → Notifications → Webhooks → Create webhook
#    Event: Order creation
#    Format: JSON
#    URL: https://your-bridge.example.com/shopify-to-acelle

# 2. Your bridge service (Cloudflare Worker example):
addEventListener('fetch', event => {
  event.respondWith(handle(event.request))
})

async function handle(req) {
  if (req.method !== 'POST') return new Response('', { status: 405 })

  // Verify Shopify HMAC signature
  const body = await req.text()
  const sig = req.headers.get('x-shopify-hmac-sha256')
  const expected = await hmacSha256(body, env.SHOPIFY_WEBHOOK_SECRET)
  if (sig !== expected) return new Response('Bad signature', { status: 401 })

  const order = JSON.parse(body)

  // Push to AcelleMail
  await fetch('https://acellemail.com/api/v1/events', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + env.ACELLE_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      subscriber_email: order.email,
      event: 'purchase_completed',
      data: {
        order_total: order.total_price,
        currency: order.currency,
        products: order.line_items.map(l => l.sku),
      }
    })
  })

  return new Response('ok')
}

The verify HMAC step is critical — without it anyone can spoof a Shopify webhook and trigger your automation.

WooCommerce → AcelleMail (via WordPress action hook):

add_action('woocommerce_order_status_completed', function($order_id) {
    $order = wc_get_order($order_id);
    $email = $order->get_billing_email();
    $total = $order->get_total();

    wp_remote_post('https://acellemail.com/api/v1/events', [
        'headers' => [
            'Authorization' => 'Bearer ' . ACELLE_TOKEN,
            'Content-Type' => 'application/json',
        ],
        'body' => json_encode([
            'subscriber_email' => $email,
            'event' => 'purchase_completed',
            'data' => [
                'order_total' => $total,
                'products' => array_map(fn($i) => $i->get_product()->get_sku(), $order->get_items()),
            ]
        ]),
    ]);
});

Add to your theme's functions.php or a custom plugin.

Stripe Subscriptions → AcelleMail:

# Stripe sends 'customer.subscription.created' / 'customer.subscription.updated' / 'invoice.paid'
# Forward via Stripe webhook → your endpoint:

# Express.js example
app.post('/stripe-to-acelle', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, STRIPE_WEBHOOK_SECRET);
  } catch (err) { return res.status(400).send('webhook error'); }

  if (event.type === 'invoice.paid') {
    const invoice = event.data.object;
    await fetch('https://acellemail.com/api/v1/events', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + ACELLE_TOKEN,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        subscriber_email: invoice.customer_email,
        event: 'subscription_renewed',
        data: { amount: invoice.amount_paid / 100, currency: invoice.currency },
      }),
    });
  }

  res.json({received: true});
});

Reverse-direction sync (AcelleMail → CRM):

When the post-purchase flow's "review request" comes back with a 1-star NPS, you want a sales / customer-success ticket to open in your CRM. Use AcelleMail's automation Send webhook action:

[Form submission: NPS feedback]
  Condition: score <= 6
    [Send webhook: POST https://your-crm.example.com/tickets
       body: { customer_email: '{{ subscriber.email }}', issue: 'low_nps', score: '{{ form.nps_score }}' }]

Your CRM receives, opens a ticket, assigns to a CSM. The whole loop closes without anyone manually copy-pasting.

Replenishment timing — when to nudge the next purchase:

Most products have a "natural reorder cycle" — coffee at 4 weeks, supplements at 30 days, razors at 6 weeks. Set the cross-sell Wait step to ~80% of the typical cycle so the email arrives before they think about reordering, not after they've already gone to a competitor. For unknown products, default to 30 days and measure CTR by Wait-duration A/B test (split the audience: 21d vs 30d vs 45d, compare conversion).

Test the full flow before launching:

In AcelleMail, the automation Test button (or Preview run) lets you simulate a subscriber going through the entire flow with shortened wait times — useful before launching for real.

# Manual test from API:
curl -X POST "https://acellemail.com/api/v1/events" \
  -H "Authorization: Bearer $ACELLE_TEST_TOKEN" \
  -d '{
    "subscriber_email": "[email protected]",
    "event": "purchase_completed",
    "data": {"order_total": 87.50}
  }'

Then watch the automation logs to verify each step ran + when.

Related articles

10 comments

7 comments

  1. Thuỳ
    solid walkthrough. the conditional-branching example especially — most automation guides skip that and you end up rebuilding from scratch.
  2. Quân
    What's the max number of steps in a sequence before performance becomes a concern? Asking because we have a 14-step nurture and I'm wondering if it's overkill
    1. Admin
      14 steps is nowhere near a performance ceiling. There's no hard cap on steps in a sequence, and the cost scales with how many subscribers are sitting in the automation at once, not with how long the sequence is. A 14-step flow with 500 active subscribers is cheaper to run than a 3-step flow with 50,000. The thing that actually bites is wait steps: each subscriber parked on a wait is a row the scheduler wakes up and re-checks, so lots of short waits (hourly) across a big list costs more than a few long ones (daily). The real risk with 14 steps in a post-purchase flow isn't the server, it's attrition. By step 8 or 9 you're usually past the window where the purchase is still fresh, and unsubscribes climb. Look at your per-step open rate in the automation report. If it flatlines around step 6, the last eight are just costing you list health for no return. I'd rather see six steps that get read than fourteen that get filtered. If you do hit something that feels slow, tell me the step count and roughly how many subscribers are mid-flow and I'll look at it. I haven't seen a step count cause trouble yet.
  3. Ravi
    Built a 9-email welcome series last quarter using this pattern. Took 4 days end-to-end. Open rate on email 1 is 62%, drops to 28% by email 9 — which is actually higher engagement than our broadcast list. Highly recommend the format. 👀
  4. Linh
    How do you handle subscribers who join mid-sequence (e.g. via API)? Do they start at step 1 or pick up at a current point?
    1. Admin
      They start at step 1. The automation has no concept of "catching up" to where the rest of the cohort is, an API-added subscriber enters at the top of the sequence and walks it from the beginning, same as someone who signed up through a form. For post-purchase specifically that's usually what you want, since the thank-you email should follow the purchase, not the calendar. Where it bites is if you're backfilling old customers via API, they'll all get the day-1 thank-you for a purchase from six months ago. If that's your case, import them into a separate list that isn't wired to the sequence, or gate the first step on a date condition so anything older than N days drops out. If you actually need a mid-sequence entry point, that's not supported today and I don't have it planned. Tell me the use case and I'll look at it.
  5. Anna
    Always test the END of the sequence first, not the start. Most testing focuses on email 1 but the longest-tenure subscribers are at the end and that's where bugs surface.
  6. Carlos
    We do almost exactly this but with one tweak — we use the 'goal' node to exit subscribers from the sequence early when they complete a target action. Saves us sending to people who already did the thing.
    1. Admin
      Early exit on a goal is the right call for this sequence, especially between the review ask and the cross-sell. Someone who already left a review and bought again does not need two more emails about it. The article walks through the linear thank/review/cross-sell path and never mentions the goal node, which is a gap on my side. I'll add it as a variant of the flow. One thing I'd want to state accurately before writing it up: whether the goal condition gets checked continuously while a subscriber sits in a wait step, or only when they arrive at the next node. That changes whether someone converting mid-wait exits immediately or still gets the next email. I'll confirm it against the runtime and put the real answer in the article rather than guess here. If you already know from watching your own numbers, that's useful to hear.
  7. Akira
    the visual flow diagram is exactly what I needed. Our welcome series has been a mess of forgotten branches — going to redo it tonight using this as the template.

More in Automation