Failed payments are the silent revenue tax of subscription businesses. A meaningful share of what gets called "churn" is actually involuntary: a card expired, a soft decline never recovered, an insufficient-funds retry that nobody noticed had ended unsuccessfully. An agent designed for this workflow can recover a non-trivial fraction of that revenue, provided it does not become an email-spam machine in the process.
This walkthrough covers the setup that pairs cleanly with Stripe Smart Retries. The agent classifies failures, picks per-type outreach, escalates the cases a human should see, and respects per-customer rate limits.
What this agent does
The agent listens to two Stripe webhook events: invoice.payment_failed for subscription invoices and charge.failed for one-time payments. For each event, it:
- Reads the failure code (
card_declined,expired_card,insufficient_funds,do_not_honor,fraudulent, etc.). - Classifies into a recovery bucket.
- Picks an outreach path matched to the bucket and customer profile.
- Either schedules an action (email, retry, escalation) or hands off to a human.
It does not bypass Stripe's own retry logic, does not charge cards out-of-band, and does not modify subscription state without explicit configuration.
For broader webhook-driven agent patterns, see how to write a prompt for a recurring agent and how to give agent multiple tools.
Failure classifier
Stripe surfaces two useful fields: failure_code and decline_code. Group them into four buckets.
- Soft decline.
insufficient_funds,generic_decline,try_again_later. Retry on Stripe Smart Retries schedule. - Card data issue.
expired_card,incorrect_cvc,incorrect_number. Customer must update payment method. - Hard decline.
do_not_honor,card_velocity_exceeded,stolen_card,fraudulent. No retry, escalate. - Unknown. Anything else. Escalate.
The classifier is deterministic and small; the LLM is not the right tool for this step. A switch statement on Stripe's documented decline codes is sufficient.
Recovery paths by failure type
Each bucket has a different path.
- Soft decline path. Let Stripe Smart Retries do the retries (default). The agent emails the customer at retry attempt 2 with a courteous heads-up. If retries succeed, the agent thanks the customer.
- Card data issue path. The agent emails immediately with a one-click update-payment-method link (Stripe Customer Portal or your own). Reminder at +3 days, +7 days. Stops at +14.
- Hard decline path. No retry. The agent escalates to a human in your system, with full context (decline code, last successful payment, customer LTV).
- Unknown path. Escalate to human, log the failure code so you can update the classifier.
Each path has its own template set, calibrated against your tone. The customer who has paid for two years deserves softer copy than the customer who joined yesterday.
Working with Stripe Smart Retries
Stripe Smart Retries already retry payments on a learned schedule that outperforms naive fixed schedules. The agent's job is not to replace this; it is to wrap it with customer-facing outreach.
Configure your Stripe account to use Smart Retries (or your own scheduled retries if you have a reason). The agent reads invoice.payment_failed and invoice.paid events to understand whether the retry succeeded. Outreach is timed against retry attempts, not against arbitrary calendar days.
For more on agent-tool boundaries, see AI agent tool use explained.
When to escalate to a human
Five triggers escalate immediately, regardless of failure code:
- Invoice value above the VIP threshold. Set a value (often $500 or $1,000 ARR equivalent) above which the agent always involves a human.
- Customer flagged as enterprise. Account manager is on the loop.
- Stripe Radar flag. Fraud signals are not retried by an agent.
- Two consecutive failures on the same card. Likely needs a human conversation.
- Open support ticket about the failure. Already a human conversation.
The handoff includes failure context, customer history, and a recommended next action. The human's job is to decide, not to gather context.
Guardrails
- Max 2 failure emails per customer per 30 days. Bundle multiple failures.
- No retries the agent initiates. Stripe owns the retry mechanics.
- No subscription cancellation by the agent. Even after exhausted retries; that is a human or business-policy decision.
- Idempotency on every webhook. The agent must handle Stripe's at-least-once delivery.
- Audit log per recovery attempt. Per failure code, per customer, per outreach.
For broader operational guardrails, see AI agent safety and guardrails. For monitoring patterns, see how to monitor agent activity.
Common mistakes
- Duplicating Stripe Smart Retries. The agent's retries fight Stripe's retries. Pick one.
- Spamming on every failure. Bundle by customer; rate-limit per 30 days.
- Treating expired cards like hard declines. Expired cards recover at high rates with one good email.
- Ignoring fraud flags. Recovering a fraudulent payment is worse than losing the original revenue.
- No idempotency. Stripe redelivers webhooks. Without idempotency, customers get four duplicate emails.
Frequently asked questions
What does a Stripe failed-payment recovery agent do?
It listens for invoice.payment_failed and charge.failed webhooks from Stripe, classifies the failure (insufficient funds, expired card, do not honour, soft decline, hard decline), and picks the right outreach: a retry on a smarter schedule for soft declines, an update-payment-method email for expired cards, an immediate human handoff for high-value or fraud-flagged failures.
Should the agent retry on its own?
Stripe Smart Retries already handles a lot of this; the agent's job is to wrap it with the customer-facing outreach piece. For soft declines, let Stripe retry on its schedule. For expired cards, the agent emails the customer with a one-click update link. For hard declines (do not honour, fraudulent), the agent escalates to a human and disables further retries.
How do I prevent the agent from spamming a customer with retry emails?
Per-customer rate limits. No more than two failure emails per 30 days. Group multiple failed invoices into a single message rather than sending one per invoice. The agent dedupes by customer ID and bundles. Spam fatigue causes voluntary churn worse than the original failure.
What signals tell the agent to escalate to a human?
Invoice value above your VIP threshold, customer flagged as enterprise, fraud signal from Stripe Radar, second consecutive failure on the same card, or an inbound support ticket related to the failure. Any of these triggers a human handoff. The agent provides context (failure code, history, customer LTV) so the human does not have to dig.
Does this work for one-time payments or only subscriptions?
Both. For subscriptions, the agent reads invoice.payment_failed and works the recovery loop. For one-time payments (charge.failed), the agent emails the customer with a re-pay link that re-uses the original payment intent or creates a new one. The classifier and outreach paths are similar; only the retry mechanics differ.
Three takeaways before you close this tab
- Classify, then act. Soft, card-data, hard, unknown.
- Wrap Stripe; do not replace it. Smart Retries owns the retry loop.
- Bundle and rate-limit outreach. Spam fatigue churns worse than the failure.
Sources
- Stripe, "Smart Retries documentation", retrieved 2026-05-10, docs.stripe.com/billing/smart-retries
- Stripe API, "Decline codes and failure codes reference", retrieved 2026-05-10, docs.stripe.com/declines/codes
- Stripe, "Webhook event types: invoice.payment_failed", retrieved 2026-05-10, docs.stripe.com/api/events
- Aryan Agarwal, "Gravity payment-recovery guardrails", internal v1, May 2026, About