How to Re-Engage Churned Subscribers with an AI Winback Email via Resend
Build a Spojit workflow that runs weekly, finds recently cancelled Stripe subscriptions, drafts a tailored winback offer per customer with AI, sends it from your own domain through Resend, then logs the touch in Monday.com and adds the contact to a Klaviyo winback list.
What This Integration Does
Subscription churn is rarely permanent. A customer who cancels this month is often one good offer away from coming back, but generic "we miss you" blasts get ignored and re-mailing the same person every week burns goodwill. This workflow targets your highest-value churners individually: it reads their actual spend history, lets an Agent-mode Connector node write a winback message that references how much they invested with you, and sends it from a domain your customers already trust. Low-value or already-contacted churners are skipped, so every send is deliberate.
A Schedule trigger fires the workflow once a week. A Stripe list-subscriptions call (filtered to canceled) gathers the recently lapsed accounts, a Loop node walks each one, and a Stripe get-customer plus list-charges pair pulls lifetime spend. A Condition node keeps only the high-value churners. For each survivor, a Connector node in Agent mode drafts a personalized offer, a Resend send-email call delivers it, Monday.com update-item records that the customer was contacted, and Klaviyo add-profiles-to-list enrolls them in a winback flow. Because the touch is logged in Monday.com and a Condition checks that log first, no churner is mailed twice. Each weekly run only acts on subscriptions cancelled since the last run, and re-runs are safe.
Prerequisites
- A Stripe connection (API key) with read access to subscriptions, customers, and charges. See the Stripe connector article.
- A Resend connection and a verified sending domain in Resend, so winback emails come from your address (for example
winback@yourbrand.com). See the Resend connector article. - A Monday.com connection and a board (for example "Winback Outreach") with a status or text column where you record the contact date. Note the
boardIdand the column IDs. See the Monday.com connector article. - A Klaviyo connection and a list to receive winback contacts. Note the
listId. See the Klaviyo connector article. - A spend threshold in mind (for example lifetime spend over $200) that defines a "high-value" churner for your business.
Step 1: Schedule the weekly run
Add a Trigger node and set its type to Schedule. Schedule triggers use a 5-field Unix cron expression plus an IANA timezone. To run every Monday at 9:00 AM Sydney time, enter:
0 9 * * 1
Australia/Sydney
The trigger output is { scheduledAt }, which you can reference later as {{ trigger.scheduledAt }} when you want to stamp the run date. A weekly cadence keeps your winback offers feeling intentional rather than spammy. Run the workflow once a week so you only act on the most recent cancellations.
Step 2: List recently cancelled subscriptions in Stripe
Add a Connector node on the Stripe connector in Direct mode and choose the list-subscriptions tool. Direct mode is right here because this is a single, predictable fetch with no AI cost. Set the inputs:
status:canceledlimit:100(the maximum per page)
Name the output variable, for example cancelled. The result is a list of subscription objects, each carrying the cancelling customer's ID and the cancellation timestamp. Stripe returns the most recent cancellations first, so a weekly run with limit 100 comfortably covers a normal week of churn. If you ever exceed a page, use the starting_after cursor with a second call.
Step 3: Loop each churner and pull spend history
Add a Loop node in ForEach mode and point it at the subscription list, for example {{ cancelled.data }}. Each pass exposes one subscription as the loop item (for example {{ item }}), from which you read the customer ID.
Inside the loop, add a Connector node on Stripe in Direct mode with the get-customer tool to fetch the full customer record (name, email, metadata):
id: {{ item.customer }}
Then add a second Stripe Direct mode node using list-charges to pull that customer's payment history, filtered to the same customer:
customer: {{ item.customer }}
limit: 100
Name the outputs (for example customer and charges). You now have the churner's identity, email, and every charge they ever made, which is the raw material for a spend-based decision and a personalized offer.
Step 4: Keep only high-value churners (and skip anyone already mailed)
Before spending AI credits, gate the loop with a Condition node. The cleanest pattern is to compute lifetime spend first: add a Connector node on the math connector using sum over the charge amounts from {{ charges.data }}, or use a small Transform node to total them. Then in the Condition node, branch on whether that total clears your threshold, for example lifetime spend greater than 20000 (Stripe amounts are in the smallest currency unit, so $200 is 20000).
To avoid re-mailing the same churner twice, add a Monday.com list-items lookup (Direct mode) against your "Winback Outreach" board and add a second clause to the Condition: continue only when no item already exists for this customer's email. Route the true branch into the AI drafting step; let the false branch fall through to the next loop iteration so low-value or already-contacted customers are quietly skipped. Reject-style halting is not needed here because a Condition simply does not run the true branch when it is not met.
Step 5: Draft a tailored winback offer with AI
Add a Connector node and switch it to Agent mode. Agent mode lets the agent reason over the customer's history and produce a tailored message, and its Response Schema forces clean JSON you can map into the email. In the prompt, hand it the facts you gathered:
Write a short, warm winback email to a customer who recently cancelled
their subscription. Reference their loyalty without being pushy and offer
a 20% discount to return.
Customer name: {{ customer.data.name }}
Lifetime spend: {{ spendTotal }} (smallest currency unit)
Number of past payments: {{ charges.data.length }}
Return JSON with: subject, body_text.
Set a Response Schema so the output is reliably structured:
{
"type": "object",
"properties": {
"subject": { "type": "string" },
"body_text": { "type": "string" }
},
"required": ["subject", "body_text"]
}
Name the output (for example draft). Because this runs inside the loop, each high-value churner gets a message written for their specific spend level. Agent mode consumes AI credits, which is exactly why the Condition in Step 4 runs first: you only pay to draft for customers worth winning back. If you want to scaffold any of these nodes quickly, ask Miraxa, the intelligent layer across your automation, something like "Add a Connector node in Agent mode that drafts a winback email from {{ customer.data.name }} and returns subject and body_text."
Step 6: Send from your domain with Resend
Add a Connector node on the Resend connector in Direct mode and select the send-email tool. Resend sends from your own verified domain, which lands better than a generic relay for a winback offer. Map the AI draft into the fields:
from: winback@yourbrand.com
to: {{ customer.data.email }}
subject: {{ draft.subject }}
text: {{ draft.body_text }}
The sending domain must be verified in Resend first or the call will be rejected. Keep the from address consistent (for example a dedicated winback@ mailbox) so replies and deliverability stay clean. This is the one customer-facing send in the workflow; everything after it is internal bookkeeping.
Step 7: Log the touch in Monday.com and enroll in Klaviyo
To make the "never mail twice" guarantee real, record the contact. Add a Connector node on Monday.com in Direct mode using update-item (or create-item if no row exists yet) against your "Winback Outreach" board. Stamp the contacted date and the customer's email into your columns:
boardId: 1234567890
itemId: {{ existingItem.id }}
columnValues: { "status": "Contacted", "date_col": "{{ trigger.scheduledAt }}", "email_col": "{{ customer.data.email }}" }
Finally, add a Connector node on Klaviyo in Direct mode with add-profiles-to-list to drop the contact into your winback flow's list:
listId: ABC123
profileIds: [ "{{ profile.id }}" ]
If you do not already have the Klaviyo profile ID, resolve or create it first with create-profile using {{ customer.data.email }}, then pass its ID into add-profiles-to-list. Once the customer is on the list, your existing Klaviyo winback automation handles follow-up nurture. The loop then moves to the next churner.
Tips
- Tune your spend threshold to your economics. Remember Stripe amounts are in the smallest currency unit, so $200 is
20000, not200. - Cap the offer. A fixed discount in the prompt keeps the AI from inventing terms you cannot honor. Keep the prompt explicit about what it may and may not promise.
- Use a dedicated
winback@address on your verified Resend domain so winback replies are easy to triage and do not mix with transactional mail. - Ask Miraxa "Why did my last run fail?" if a send is rejected; it can read the run and point you to the failing node.
Common Pitfalls
- Re-mailing the same churner. If you skip the Monday.com lookup in the Condition, a customer who cancelled weeks ago will keep matching
canceledand be mailed every run. The log check is what makes the workflow idempotent. - Unverified Resend domain. The
send-emailcall fails until the sending domain is verified in Resend. Verify it before the first live run. - Currency-unit confusion. Comparing a raw Stripe amount (cents) against a dollar threshold will mis-target everyone. Total and compare in the same unit.
- Pagination on heavy churn.
list-subscriptionsreturns up to 100 per page. If a week's cancellations exceed that, follow thestarting_aftercursor or you will silently miss churners.
Testing
Before going live, narrow the blast radius. Temporarily set the Condition threshold very high so only a single known test customer passes, and point the Resend to field at your own inbox instead of {{ customer.data.email }}. Run the workflow with the Run button rather than waiting for the schedule, then open the execution log to confirm the Stripe fetch, the AI draft, the Resend send, the Monday.com log, and the Klaviyo enrollment all succeeded. Once the draft quality and the "skip already-contacted" logic look right on one customer, restore the real threshold and recipient and let the Schedule trigger take over.