Recover failed Stripe payments with Supabase context and personalized retry emails

When a Stripe payment fails, pull the customer's history from Supabase, log the failure, alert revenue ops in Slack, and send a retry email matched to the customer's tier.

Agentic Task
StripeSupabaseSlack BotResendFinanceCustomer SupportOperationsNotifications & AlertsEmail AutomationData Sync

Build an agent workflow that turns every failed Stripe payment into a fully contextualized, personalized recovery action across Stripe, Supabase, Slack, and Resend.

Trigger: a Stripe webhook. The workflow should fire whenever Stripe emits charge.failed or invoice.payment_failed. The incoming webhook payload contains the charge or invoice object — use it as the entry point.

When the webhook fires, the agent should:

1) Hydrate the Stripe context. Call Stripe Retrieve Charge with the charge id from the webhook (or Retrieve Invoice if it's an invoice.payment_failed event, then pull the customer id from the invoice). Then call Stripe Retrieve Customer to get the full customer object. Capture the failure reason, amount (remember Stripe amounts are in the smallest currency unit), currency, and customer email.

2) Pull internal customer history from Supabase. Use Supabase Get Row on the customers table filtered by the Stripe customer id (or email) to retrieve plan tier, account owner, and lifetime value. Then use Supabase Get Many Rows on the subscriptions table filtered by that customer to read subscription history: how long they've been a customer, current plan, MRR, prior renewal events, and any prior payment failures. If the customer is not found in Supabase, fall back gracefully to the Stripe data and note the gap in the alert.

3) Log the failure to Supabase. Use Supabase Create Row on a payment_failures table with at minimum: stripe_customer_id, stripe_charge_id (or invoice id), failure_reason, amount, currency, customer_email, account_tier, and a timestamp. This becomes the durable record of what happened.

4) Decide a recommendation. Based on the customer's history, the agent should pick one of: "automatic retry" (low-value or newly failed account, likely transient), "downgrade or pause" (recurring failures on a higher plan that may warrant offering a cheaper tier), or "churn risk — escalate" (high-LTV or long-tenured customer whose card has now failed). Write the recommendation as a single short line.

5) Post a Slack alert. Use the Slack Bot Send a Message operation to post in #revenue-ops. Include: customer name and email, plan tier and MRR, lifetime value, failure reason and amount, time since the customer joined, count of any prior failures, and the one-line recommendation. Keep it scannable — a short header line, a few bullet-style fields, and the recommendation at the bottom.

6) Send a personalized retry email through Resend. Use Resend Send Email to message the customer. The tone and content must be matched to their history, not a generic dunning template:

• Trial or low-tenure customer → friendly, low-pressure nudge with a clear retry link and a quick reassurance that it's usually a card issue.

• Established paying customer (mid LTV, several months tenure) → warmer, more direct ask, acknowledge their history, give them the retry path and an offer to chat.

• High-LTV or long-tenure customer → account-manager style, mention their tenure or specific plan, offer a direct line to the account owner, and treat the retry as a courtesy rather than a demand.

The email should have a real subject line, a clear update-your-card call to action, and a sign-off that matches the recommended tone. Send it from a verified Resend domain (do not hardcode a domain — let the user configure it).

Constraints: do not send a retry email if the failure_reason indicates fraud or a disputed charge — only alert Slack in that case. If the same customer has had more than two failures in the last 14 days (visible from the payment_failures table), skip the email and explicitly flag the Slack alert as "churn risk — escalate" instead. The agent should pick the recommendation and the email tone — not run a fixed template.

Auth and config to expect: Stripe secret key, Supabase project URL and secret key (Supabase tables involved: customers, subscriptions, payment_failures, all in the public schema), Slack bot OAuth, Resend API key with a verified sending domain. The Slack channel (#revenue-ops) and the from-address for Resend should be configurable inputs.

Additional information

What does this prompt do?
  • Listens for failed Stripe payments and instantly pulls the full charge, customer, and account history for that account.
  • Looks up the customer in your Supabase database to gather subscription history, lifetime value, and current plan tier.
  • Logs every failure to a payment_failures table so you have a clean record of what went wrong, when, and how much was at stake.
  • Posts a Slack alert in your revenue ops channel with the customer context and a one-line recommendation: retry, downgrade, or treat as a churn risk.
  • Drafts and sends a personalized retry email through Resend, with tone and content matched to the customer's value and history, not a generic dunning template.
What do I need to use this?
  • A Stripe account where you can add a webhook for failed charges and invoice payment failures.
  • A Supabase project with a customers table and a subscriptions table the agent can read from.
  • A payment_failures table in Supabase (or permission to create one) for logging.
  • A Slack workspace and the channel where revenue ops should be alerted.
  • A Resend account with a verified sending domain for the retry emails.
How can I customize it?
  • Change which Slack channel gets pinged, or route different tiers to different channels (for example, high-value accounts to a VIP escalation channel).
  • Adjust the tone rules the agent uses to draft the retry email, such as which language to use for trial users versus long-tenured paying customers.
  • Add extra Supabase tables to the lookup (usage data, support tickets, NPS scores) so the agent can factor more signal into its recommendation.
  • Decide which Stripe events trigger the workflow. The default covers charge failures and invoice payment failures, but you can scope it to specific products or plans.

Frequently asked questions

What happens when a payment actually fails in Stripe?
Stripe sends a webhook to the workflow within seconds. The agent fetches the full charge and customer record, checks your Supabase tables for account history, logs the failure, posts a Slack alert, and drafts a personalized retry email. The whole thing runs end to end without you touching anything.
How does the agent decide what tone to use in the retry email?
It reads the customer's history from Supabase, including how long they have been a customer, their plan tier, and their lifetime value. A new trial user gets a friendly nudge. A long-time enterprise customer gets a more attentive, account manager style message. You can adjust these rules in the prompt.
Do I need to build the payment_failures table myself?
You can create it ahead of time or let the agent set up the columns it needs on the first run. The minimum is a customer id, failure reason, amount, and timestamp. Add whatever extra context you want to track.
Will this send retry emails automatically, or just draft them?
By default it sends the email through Resend. If you would rather have it draft and wait for human approval, ask for that in the prompt and the workflow will post the draft to Slack for a one-click send.
What if the customer is not in our Supabase database yet?
The agent handles that gracefully. It falls back to whatever Stripe knows about the customer, notes in Slack that there was no internal record found, and still drafts a retry email using the Stripe data alone.

Stop losing revenue to generic dunning emails.

Connect Stripe, Supabase, Slack, and Resend once, and every failed payment gets the context, alert, and personalized recovery email it deserves.