Generative AI  

Generative AI for Revenue Recovery: Smart Dunning & Retention

Introduction

Most “AI for sales” focuses on top-of-funnel leads, yet a large share of lost revenue hides in billing failures, expiring cards, procurement hiccups, and quiet customer churn. Traditional dunning is blunt—batch emails and threats that damage relationships and still miss cash. A production-ready generative system treats revenue recovery as a policy-aware, evidence-backed workflow: it diagnoses the cause, proposes the next best action, executes it through tools with receipts, and records a compact, auditable trace. This article outlines the architecture and shows a live deployment that lifted collected ARR by 21% while reducing involuntary churn.


From reminders to root-cause actions

Effective recovery starts with diagnosis, not templates. The assistant ingests payment events, gateway error codes, contract terms, procurement notes, and recent support tickets. Instead of “Your card failed,” it classifies the issue (card expiry, SCA challenge, ACH micro-deposit mismatch, PO pending, vendor registration delay, invoice dispute) and maps each to policy-bound actions (update card link, resend SCA step-up, re-initiate micro-deposits, open procurement ticket, route to dispute resolution). Each action must return a receipt (payment intent ID, ticket ID, form submission ID), so success is verifiable—not assumed.


Evidence and eligibility over long context

Stuffing entire CRM histories into the prompt slows everything down and confuses the model. Use eligibility rules to pass only high-signal evidence: the latest invoice and status, last three gateway responses, contract auto-renew terms, current PO/state, and a summary of any open support issues. Prefer structured features (error codes, IDs, due dates, country, currency) and minimal-span citations (the two lines in the MSA that govern grace periods) over long prose. If a required element is missing (no valid payment method on file), the assistant must ask a focused question or trigger a safe tool path—never guess.


Tools first, prose second

Dunning succeeds when systems take action. Bind the assistant to typed tools:

  • CreatePaymentIntent(amount, currency, customer_id)pi_…

  • SendSecureUpdateLink(channel, customer_id, expires_in)link_…

  • ScheduleSCAChallenge(pi_id, method)sca_…

  • OpenProcurementTicket(account_id, vendor_portal)TCK-…

  • OfferGraceExtension(account_id, days)ext_…

  • LogContact(channel, template_id, personalization)log_…

The model proposes tool calls; the runtime validates arguments, executes, and returns receipts that are embedded in the response artifact (and emails/SMS if sent). No “we updated your card” without a payment-method token on file and a receipt ID.


Contracts, validators, and routing

Define a strict output contract—e.g., recovery_plan.v3:

{
  "account_id": "string",
  "root_cause": "card_expired|insufficient_funds|ach_setup|po_pending|dispute|other",
  "recommended_action": "update_card|retry_charge|send_sca|open_procurement|start_dispute_flow|extend_grace",
  "tool_calls": [{"name":"...","args":{...},"receipt":"..."}],
  "message_preview": "<= 45 words, policy-safe",
  "citations": ["doc:msa#L221-229","event:gw_err#2025-10-24T09:41Z"]
}

Guard with validators: schema check, policy gates (e.g., max grace days by segment), locale compliance, and channel eligibility. Route easy cases to a small model; escalate to a larger model only when validators flag ambiguity (e.g., overlapping disputes and procurement blocks).


Observability and change control

Each attempt writes a trace: prompt bundle version, retrieval snapshot IDs, tool proposals and executed receipts, message template used, and outcome labels (paid, link clicked, promise-to-pay, still delinquent). A tiny golden suite—card expiry, SCA failure, PO pending, dispute—must pass in CI for any change to prompts, policies, or templates. Rollouts happen behind a feature flag per segment and geography, with one-click rollback if guardrails trip (e.g., spike in dispute replies).


Economics you can steer

Measure $/recovered dollar, time-to-recovery, contact attempts per recovery, and negative signal rate (unsubscribes, complaints). Conciseness matters: short, policy-safe messages and minimal evidence spans cut tokens and latency, which lets you parallelize recovery at scale. Cache common treatments (e.g., “card expired + US + Visa”) keyed by (root_cause, segment, policy_version).


Real-World Deployment: Mid-Market B2B SaaS (US/EU)

Context.
A 900-employee SaaS company had creeping involuntary churn. The prior dunning system sent fixed sequences (3 emails + 1 SMS) regardless of cause. Procurement-driven delays (vendor setup, PO numbers) and SCA challenges caused most failures, but the team lacked visibility and over-contacted customers, generating friction.

Design.
They introduced a policy-aware recovery assistant wired into billing, CRM, payment gateways, and a vendor-portal ticketing bot.

  • Eligibility policy v4. Include only: last invoice, last 5 gateway events with codes, contract renewal clause span, PO status, and open support case summary; exclude free-text beyond 400 chars; force locale templates by country.

  • Contract. recovery_plan.v3 (above) with one-sentence message preview and minimal citations (contract span + last gateway event).

  • Tools. Payment intent creation, secure link sender (expiring per policy), SCA scheduling, procurement ticket opener for named portals, grace extension, and CRM log. Each returns a receipt attached to the plan.

  • Routing. “Card expired” + valid token → small model; “mixed signals” (e.g., dispute + SCA) → large model.

  • Guardrails. EU accounts require SCA step-up before retrying; grace extension capped at 10 days for SMB, 20 for enterprise; procurement tickets allowed only if PO state is “awaiting vendor setup.”

Example flows.

  • Card expired (US). Plan proposes SendSecureUpdateLink (receipt link_ab12), then RetryCharge (receipt pi_cx33) after update. Message preview: “Your card expired on 10/22; update securely here (expires in 24h). We’ll retry once it’s saved.”

  • SCA required (EU). Plan schedules ScheduleSCAChallenge (receipt sca_901f) and sends a short, localized prompt; retries are blocked until challenge success.

  • PO pending (enterprise). Plan opens OpenProcurementTicket on the customer’s Ariba portal with vendor registration payload; offers no payment link (policy), but sets a CRM task for the AE.

Outcomes over 10 weeks.

  • Recovered ARR: +21% vs. previous quarter, at similar traffic.

  • Involuntary churn: −28% (card expiry recoveries + SCA conversions).

  • Time-to-recovery (median): 3.1 days → 1.7 days.

  • Customer friction: unsubscribe/complaint rate −42%, driven by cause-specific, shorter messages.

  • Ops cost: tokens per contact −61%; $/recovered dollar −33% via concise outputs, small-model routing (68% of cases), and caching.

Incident & rollback.
A gateway briefly changed error code semantics; the classifier mis-labeled “insufficient funds” as “SCA required,” creating unnecessary challenges. Observability showed a validator failure spike. Rollback pinned the gateway mapping snapshot (receipt MAP-2025-10-18T14:02Z) while the adapter was fixed; metrics normalized same day.

What actually mattered.
Not new copywriting tricks. The lift came from root-cause classification, policy-bound actions with receipts, and concise, localized messages—plus the ability to roll back non-performing changes instantly.


Implementation starter (you can adapt today)

Bundle sketch

bundle_id: "recovery_plan.v3"
model: "gpt-5-small"
system: |
  Produce a recovery plan JSON matching the schema. Use only eligible evidence.
  One-sentence preview (≤45 words). Cite minimal spans.
retrieval_policy:
  include: ["invoice://latest","gateway://events?limit=5","crm://open_cases?summary",
            "contract://msa#renewal","po://status"]
  exclude_free_text_over: 400
  locale_from: "account.country"
validators: [SchemaCheck, PolicyGates, LocaleCompliance, RateLimitContacts]
routing:
  small_if: "root_cause in {card_expired, insufficient_funds}"
  large_if: "multiple_causes or dispute_present"
tools: [CreatePaymentIntent, SendSecureUpdateLink, ScheduleSCAChallenge,
        OpenProcurementTicket, OfferGraceExtension, LogContact]
guardrails:
  - "eu_account => require_sca_before_retry"
  - "grace_days <= segment_cap"
metrics:
  primary: "recovered_arr"
  secondary: ["time_to_recovery","$/recovered","complaint_rate"]

Conclusion

Revenue recovery is not a mail merge; it’s a decision system. When you frame dunning as evidence-driven diagnosis plus policy-bound actions—with receipts, concise messages, and tight observability—you convert avoidable churn into retained revenue without burning goodwill. The SaaS deployment shows the pattern: understand the cause, act through tools, keep outputs short and auditable, and ship changes behind flags. Do that, and “please update your card” turns into cash in the bank—with a paper trail your CFO and counsel will both sign.