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 Automation → Automations. The index lists every automation in this account with its current state:

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

For the confirmation email step:
- Trigger: Tag added
- Tag:
recent-purchaser
- 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:

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 tag → recent-purchaser:

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": "buyer@example.com",
"event": "purchase_completed",
"data": {
"order_total": 87.50,
"currency": "USD",
"products": ["yoga-mat-blue", "yoga-block-pair"],
"category": "fitness"
}
}'
In AcelleMail, build the automation:
- Trigger: Custom event, event name =
purchase_completed
- Conditional step: branch on
data.order_total > 100
- Branch A (high-value): premium review request track
- 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": "your-test-email@example.com",
"event": "purchase_completed",
"data": {"order_total": 87.50}
}'
Then watch the automation logs to verify each step ran + when.
Related articles#