Home Blog AI & Automation Claude Code CLI and the Stripe API: A Practical Workflow for Auditing Involuntary Churn and Dunning Recovery
AI & Automation

Claude Code CLI and the Stripe API: A Practical Workflow for Auditing Involuntary Churn and Dunning Recovery

The Stripe Dashboard’s Retries tab will tell you a single number: your recovery rate for failed invoice payments over the selected period. What it will not tell you is why that number is what it is, which decline reasons are actually retryable, whether your retry schedule is wasting attempts against a card network’s own limits,...

Ryan Brooks
Ryan Brooks
September 22, 2026
9 min read
2,051 words
Claude Code CLI and the Stripe API: A Practical Workflow for Auditing Involuntary Churn and Dunning Recovery

The Stripe Dashboard’s Retries tab will tell you a single number: your recovery rate for failed invoice payments over the selected period. What it will not tell you is why that number is what it is, which decline reasons are actually retryable, whether your retry schedule is wasting attempts against a card network’s own limits, or whether your dunning emails are firing fast enough to matter. Those are the questions that separate a median dunning setup from a top-quartile one, and answering them requires pulling the underlying event data, not reading the summary tile.

Claude Code CLI can authenticate against the Stripe API directly, pull charges, invoices, and event objects for a given window, and write the analysis script on the spot, which turns a question like “which decline reason is actually costing us the most recovered revenue” into a single working session instead of a week of manual CSV exports and spreadsheet joins. This is the same investigative pattern behind our HubSpot CRM data quality audit, applied to billing data instead of pipeline data.

Why the dashboard number hides the problem

Involuntary churn, revenue lost to failed payments rather than a customer actively canceling, is a real and often underweighted share of total SaaS churn. Recurly’s subscription billing research tracks this pattern across its own customer base and consistently finds failed-payment churn sitting alongside voluntary cancellation as a major loss category for recurring-revenue businesses (Recurly, Churn Rate Benchmarks). The problem is that a single blended recovery-rate number cannot tell you which lever to pull, because it averages three very different failure modes together:

  • Soft declines that a well-timed retry will likely resolve on their own, such as a temporary insufficient-funds condition.
  • Hard declines that no amount of retrying will fix, such as a closed or reported-stolen card, where retrying just burns attempts against network limits for no chance of recovery.
  • Expired or soon-to-expire cards that a proactive card-updater check should catch before the renewal charge ever fires.

Stripe’s own documentation draws this same distinction: it classifies decline codes like insufficient_funds and the ambiguous do_not_honor response as generally retryable, while explicitly permanent codes are not (Stripe Docs, Declines). A recovery program that treats all declines the same way is, by definition, wasting effort on the hard declines and probably under-retrying the soft ones.

Two ways into the underlying data

There are two legitimate paths to get past the dashboard summary:

  • The Stripe REST API, querying the Charges, Invoices, and Events endpoints directly with a restricted, read-only API key. This is the right tool for a scoped pull, such as every failed invoice payment in the last 90 days with its decline code and retry count attached.
  • Stripe Sigma, Stripe’s own SQL-based reporting product, for teams that need to join billing data against larger historical windows or run more complex aggregate queries than a scripted API pull comfortably handles.

For most mid-market B2B SaaS and fintech accounts, a restricted API key scoped to read-only access on Charges, Invoices, and Events is enough. Sigma becomes worth setting up once the analysis needs to span a full year of billing history or join against data Stripe does not expose through the standard API.

The Investigation Loop
1

Connect
A restricted, read-only Stripe API key, scoped to Charges, Invoices, and Events
2

Ask
A specific question, like which decline code drives the most unrecovered MRR
3

Analyze
Claude writes and runs the query against the pulled data, and shows its work
4

Iterate
The follow-up question runs immediately, in the same session

The Four-Signal Recovery Audit

Once the raw event data is pulled, the actual audit comes down to four signals. Each one answers a different question about where recovery revenue is being left on the table, and each is a query you can run in a single Claude Code CLI session against the pulled Stripe data.

The Four-Signal Recovery Audit
1

Decline Reason Mix
What share of failures are soft, hard, or expired-card, and is spend chasing the wrong bucket
2

Retry Cadence Effectiveness
Which attempt number in the schedule actually recovers the invoice, and whether attempts are spaced against network limits
3

Card Updater Catch Rate
What share of soon-to-expire cards get refreshed before the renewal charge ever fires
4

Dunning Timing Lag
Elapsed time between the failure event and the first recovery email, and how that lag tracks against cancellation

Signal 1, Decline Reason Mix, is the query that reframes everything else: pull every failed PaymentIntent or Invoice in the window, group by decline code, and classify each against Stripe’s own soft-versus-hard taxonomy. A book of business where 40% of failures are hard declines needs a very different response than one where the failures are almost entirely temporary insufficient-funds events.

Signal 2, Retry Cadence Effectiveness, looks at which retry attempt number in the sequence actually recovers the payment. Stripe’s Smart Retries feature uses a machine-learning model trained on dynamic signals, including device and timing patterns, to choose retry timing rather than a fixed schedule, and it is configurable to retry for anywhere from one week up to two months (Stripe Docs, Automatic Collection; Stripe Engineering, How We Built It: Smart Retries). If your recovery curve shows most successful retries clustering on attempt one or two and then flatlining, either the later attempts are hitting hard declines that were never going to convert, or the retry window is too short for genuinely temporary failures like a paycheck-timing insufficient-funds decline to resolve.

Signal 3, Card Updater Catch Rate, checks how many cards that were within a normal expiration window before their next renewal actually got a fresh card number on file versus how many hit a dead card at charge time. A low catch rate here means failures are being generated that a purely proactive check would have prevented entirely, before a retry or a dunning email is ever needed.

Signal 4, Dunning Timing Lag, measures the gap between the failure event and the first customer-facing notification, then correlates that lag against which accounts recovered and which canceled. A dunning sequence that fires the first email hours after a failure behaves very differently from one that waits until the next billing cycle is already at risk.

What the dashboard shows you, and what the audit adds

Question Stripe Dashboard (Retries tab) Four-Signal API Audit
Overall recovery rate Yes, as a single blended percentage Yes, plus broken out by decline reason and plan segment
Which decline codes are wasting retry attempts No Yes, classified against Stripe’s own soft/hard taxonomy
Which retry attempt number actually recovers revenue No Yes, per-attempt recovery curve
Card Updater catch rate before renewal No Yes, joined against upcoming renewal dates
Notification lag vs. cancellation correlation No Yes, event-timestamp level

A representative look at what that breakdown produces, illustrative only and not a real client’s figures:

Illustrative Example, Not Real Client Data
90-Day Failed Payment Breakdown (Sample B2B SaaS Account)
Decline Reason Mix
Soft decline (insufficient funds)44%
Soft decline (do_not_honor)27%
Expired / soon-to-expire card19%
Hard decline (closed / fraud flag)10%
Recovery Rate by Retry Attempt
Attempt 131%
Attempt 222%
Attempt 39%
Attempt 4+3%
Card Updater catch rate58%
Avg. lag, failure to first email19 hrs
In this invented example, nearly a fifth of failures trace back to expired cards a stronger Card Updater configuration should have caught, and recovery drops off sharply after the second retry, a signal the schedule may be burning later attempts on declines that were never going to convert.

What to do with what the audit finds

  • If hard declines are a meaningful share of failures: stop retrying them. Card networks cap how many times a merchant can resubmit a declined transaction within a rolling window and can fine merchants who exceed those limits on non-retryable codes, so every wasted attempt against a permanent decline is pure downside (Visa Acceptance Solutions Support).
  • If Card Updater catch rate is low: confirm it is actually enabled on the account and that the billing cycle gives it enough lead time before the renewal charge to receive an updated card number.
  • If recovery falls off sharply after attempt one or two: compare the retry schedule against the decline mix. Soft declines tied to pay-cycle timing often need a schedule that spans at least a couple of weeks, not a handful of retries compressed into 48 hours.
  • If timing lag correlates with cancellation: move the first customer-facing notification earlier, and treat the email as an action prompt with a direct link to update payment details rather than a generic receipt-style notice.

Setting up the pull

None of this requires write access to the Stripe account. Create a restricted API key scoped to read-only access on Charges, Invoices, Events, and Customers, and keep it separate from any key used elsewhere in the stack. From there, a Claude Code CLI session can pull the relevant objects for a defined window, join them against renewal dates for the Card Updater check, and produce the four-signal breakdown in a single sitting instead of a manual export-and-join exercise repeated every quarter. Once the schedule and messaging changes from the audit are live, the same pull run again 60 to 90 days later shows whether the changes actually moved the recovery curve, not just whether they felt like the right call.

This is the same category of work we cover in our guide to auditing CRM data quality with Claude Code CLI and the HubSpot API, and the two audits pair well for RevOps teams: one confirms the pipeline data feeding the board deck is trustworthy, the other confirms the recovered-revenue number sitting next to it is too.

Want your billing data wired up for this kind of investigation instead of a monthly glance at the Retries tab? See how MV3 sets up Analytics MCP and API access, or start with a GEO audit if you want a broader look at your AI-visibility and analytics setup together.


Ryan Brooks
Ryan Brooks LinkedIn
Technical SEO Lead, MV3 Marketing

Ryan Brooks leads technical SEO at MV3 Marketing, specializing in schema architecture, entity graphs, crawlability, and the structural signals that determine whether AI answer engines cite a page.

Ready to audit your organic growth opportunity?

$2,500 flat. 5 business days. Six deliverables tied to pipeline , not rankings. No retainer required.

Get the Organic Growth Audit →

Turn Your Organic Channel into a Revenue Engine.

The MV3 SEO Audit maps your full organic opportunity in 5 business days.

Get the Audit →