Recover failed Stripe payments with Customer.io and HubSpot
When a Stripe payment fails, Customer.io sends a tone-matched recovery email and high-value accounts get a HubSpot task so a CSM can step in.
Build an agent workflow that runs every time Stripe fires an invoice.payment_failed webhook, recovers the customer through Customer.io, and escalates to a human in HubSpot when the account is high value or has failed several times in a row.
Trigger: Stripe webhook on the invoice.payment_failed event.
What the agent should do on every run:
1) Read the failed invoice and customer from the webhook payload: invoice id, amount_due (cents), attempt_count, customer id, customer email, the plan or subscription name, next_payment_attempt, and hosted_invoice_url. If anything is missing, call Stripe Retrieve Invoice and Retrieve Customer to fill in the gaps.
2) Call Customer.io Identify Person on the customer's email and upsert these traits: last_payment_failed_at (current ISO timestamp), failed_invoice_id, failed_invoice_amount (in dollars), failed_plan_name, dunning_attempt (mirror Stripe's attempt_count), and next_payment_attempt_at.
3) Call Customer.io Send Transactional Email using a pre-built dunning template, choosing tone from attempt_count: first failure is a warm, gentle reminder pointing to the billing portal link with the next retry date; second failure is a firmer reminder noting Stripe is still retrying and asking them to update payment; third or later failure is a serious tone explaining the risk of service interruption. Pass the template the customer first name, plan name, amount formatted as dollars, hosted_invoice_url, and next_payment_attempt_at as message data.
4) Decide whether to also escalate to a human. Escalate if EITHER the failed amount is above a configurable threshold (default $500, i.e. 50000 cents) OR attempt_count is 3 or more. When escalating: look up the contact in HubSpot with Get Contact by email, then call HubSpot Create Task associated with that contact. The task subject should read like 'Recover failed payment from {customer name}: ${amount} on {plan}', due tomorrow, priority HIGH, with a body that summarizes attempt count, plan, the failure reason if available, and the hosted invoice URL so the CSM can act from one place. If the HubSpot lookup returns no match, log the skip and finish the run without creating a task.
Keep the workflow idempotent. If Customer.io already holds the same failed_invoice_id with this dunning_attempt and the transactional email has already been sent for it, skip the resend and only run the HubSpot escalation step if it is also new.
Integrations used: Stripe (trigger plus Retrieve Invoice, Retrieve Customer), Customer.io (Identify Person, Send Transactional Email), HubSpot (Get Contact, Create Task).
Things I want to tweak later: the dollar threshold for HubSpot escalation, the attempt_count that always triggers escalation, the transactional message template id for each tone, and the HubSpot task owner (default to the contact's existing owner).
What does this prompt do?
- Listens for failed Stripe payments and pulls the invoice amount, plan, attempt count, and customer email automatically.
- Updates the customer's profile in Customer.io and sends a recovery email with tone matched to whether this is their first miss or a repeat failure.
- Escalates to a human in HubSpot by opening a dated task for the CSM whenever the amount is large or Stripe has already retried multiple times.
- Keeps every nudge idempotent so customers never get spammed with duplicate emails when webhooks fire twice.
What do I need to use this?
- A Stripe account where you can enable webhooks on failed invoice payments.
- A Customer.io workspace with one or more transactional email templates built for dunning reminders.
- A HubSpot account that holds your billing contacts so the workflow can look them up and create tasks against them.
How can I customize it?
- Change the dollar amount that triggers human follow-up in HubSpot. Default is $500 and up.
- Pick which Customer.io template fires for each stage: gentle nudge, firmer reminder, or final warning.
- Decide who owns the HubSpot task: the contact's existing owner, a named CSM, or your billing team.
- Tune the retry count that escalates to a human. By default the third failed attempt always gets a task, no matter the amount.
FAQs
Does this replace Stripe's automatic retry schedule?
Will the customer get the same email twice if a webhook fires more than once?
What happens if the customer is not in HubSpot yet?
Can the email tone really change based on how many times the card failed?
Do I need a paid HubSpot plan for this to work?
Related templates
See every open conversation next to that customer's plan, monthly value and unpaid invoices, so the expensive account never sits waiting all morning.
Pick a client and a date range to see sent, replies, meetings booked and the real deal value your cold email produced, campaign by campaign.
Work every partner tier decision from one board, with the revenue and commission numbers, clear promotion thresholds, and AI review briefs.
Open one board at month end to find every closed deal missing a commission, every commission with no deal behind it, and every amount that does not add up.
Open one desk each morning to see every account still in a trial, ranked by how much money is at stake against how little they have actually used.
Open one board each morning to see which of your accounts are hiring, what they are building, and where your product fits the roles they just opened.
Stop losing revenue to silent churn.
Connect Stripe, Customer.io, and HubSpot once. Recovery runs itself, and humans get pulled in only when an account is worth the effort.