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).
Additional information
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.
Frequently asked questions
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?
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.