Skip to main content
AI Billing Agent: 4 Silent Bugs That Break Cash Flow

AI Billing Agent: 4 Silent Bugs That Break Cash Flow

AI Integration
••5 min read•By Daily Miranda Pardo

An AI billing agent has 48 hours in production before it breaks — if you skip the four guardrails that every tutorial conveniently leaves out.

The demo works. The LLM generates payment reminders, sends emails, updates statuses in Notion. Clean. But three weeks later you have a client who received the same reminder six times, another who got charged twice, and a retry loop that has been running since Tuesday without anyone noticing.

This is not a model problem. This is an architecture problem.

Why the Demo Isn't Production

The demo lives in a clean context: one invoice, one client, zero retries, zero network failures, zero concurrent executions. Production has all of that at once.

The four failures I see repeated in client implementations — before they come to us — are structural, not prompt-related. Tweaking the model or adjusting temperature won't fix them.

The 4 Bugs That Destroy Cash Flow

Bug 1: No idempotency on invoice generation

The agent listens for a "service completed" webhook and generates the invoice. Perfect. Now the webhook arrives twice — a timeout on the client side, an automatic retry from the provider. The agent generates two invoices. The client gets charged twice.

The correct pattern is an idempotency key derived from the event:

async function createInvoice(event: ServiceCompletedEvent) {
  const idempotencyKey = `invoice-${event.serviceId}-${event.clientId}`;
  
  const existing = await db.invoices.findUnique({
    where: { idempotencyKey }
  });
  
  if (existing) return existing; // already processed, return without creating
  
  return db.invoices.create({
    data: {
      idempotencyKey,
      clientId: event.clientId,
      amount: event.amount,
      state: 'NEW',
    }
  });
}

Without this, every webhook retry creates a new invoice. Idempotency is non-negotiable in agents that handle money.

Bug 2: State lost between email trigger retries

The agent sends the payment reminder on day 15. The email fails (client's server is down). The agent retries in 10 minutes. But it doesn't remember it already tried to send that reminder, so it generates a new one with a different date, different reference number, possibly a different amount if there's late fee logic.

Invoice state has to persist across executions:

type InvoiceState = 
  | 'NEW' 
  | 'SENT' 
  | 'OVERDUE' 
  | 'RETRY_1' 
  | 'RETRY_2' 
  | 'RETRY_3'
  | 'ESCALATED'
  | 'PAID';

async function processInvoiceReminder(invoiceId: string) {
  const invoice = await db.invoices.findUnique({ where: { id: invoiceId } });
  
  // the state machine decides what to do based on current state
  switch (invoice.state) {
    case 'SENT':
      if (daysSince(invoice.sentAt) >= 30) {
        await transition(invoice, 'OVERDUE');
        await scheduleReminder(invoice, 'RETRY_1');
      }
      break;
    case 'RETRY_3':
      await transition(invoice, 'ESCALATED');
      await notifyHuman(invoice); // agent never acts alone past this point
      break;
  }
}

Without an explicit state machine, each agent execution recalculates where it is from prompt heuristics. That's non-deterministic behavior in a financial workflow.

Bug 3: Unlimited retries with no backoff

The agent retries the reminder when it fails. How many times? With what interval? If the answer is "as many as needed" or "it's configured in the prompt", you have an active loop running on some server right now.

The retry limit has to be in the code, not in the instruction to the model:

const MAX_RETRIES = 3;
const BACKOFF_MS = [3_600_000, 86_400_000, 259_200_000]; // 1h, 24h, 72h

async function scheduleNextRetry(invoice: Invoice) {
  const retryCount = invoice.retries + 1;
  
  if (retryCount > MAX_RETRIES) {
    await transition(invoice, 'ESCALATED');
    return;
  }
  
  const delayMs = BACKOFF_MS[retryCount - 1];
  await queue.add('send-reminder', { invoiceId: invoice.id }, { delay: delayMs });
  await db.invoices.update({
    where: { id: invoice.id },
    data: { retries: retryCount, state: `RETRY_${retryCount}` }
  });
}

Without this, the agent can chase a client for weeks, creating a legal and reputational risk.

Bug 4: No escalation to human when everything fails

This is the most critical one. Three reminders didn't work. What does the agent do? If the answer is "keep retrying", you have an agent acting autonomously in a situation that requires human judgment: negotiate a payment plan, start a collections process, decide whether it's worth pursuing at all.

The agent must know when to stop and hand control to a person. Always. No exceptions. See the ESCALATED node in the state machine above: at that point the agent notifies a human and stops. It doesn't continue. It doesn't decide alone.

Demo vs. Production-Grade Billing System

What gets built in a one-day demo:

  • LLM that generates reminder emails
  • Date-based trigger
  • Send via email API

What a billing system needs to survive in production:

  • Idempotency on invoice and reminder generation
  • Persistent state machine per invoice
  • Exponential backoff with hard retry limit
  • Mandatory human escalation after retries exhausted
  • Observability: every state transition must be auditable

If you're using our AI integration service, these guardrails are already in the base architecture. They're not configurable — they're structural.

Build it Right vs. Maintain What Was Built Fast

An implementation without these four guardrails has a real maintenance cost: the first duplicate charge, the first loop that's been running for days, the first invoice in an inconsistent state. These aren't hypothetical. They're inevitable.

Building this correctly takes longer upfront. Maintaining what was built quickly takes much longer — at the worst possible time.

If you're thinking about automating collections in your business with an AI agent, we can review the architecture before the system goes live. It's much cheaper to fix on paper than after the first cash flow incident.


Do you have a billing agent in production or are you building one? Let me know where you are and which part of the architecture is giving you the most trouble.

Let's talk on WhatsApp →

Share article

Repetitive processes in your business?

Download the free AI Automation Map — the 5 most time-consuming processes and how to fix them.

Controller: DailyMP (Daily Miranda Pardo). We use your email only to send you the PDF, unless you tick the box below. More info in the privacy policy.

Written by Daily Miranda Pardo

I help businesses automate processes, build AI agents and connect intelligent systems.