Skip to content

Automation  ·  Finance

How to build collections and dunning

A customer gets a fourth payment reminder while their renewal is on the table. The thinking behind dunning that knows better, the prompts that build it, and what it takes to keep it running.

Built with Tray Headless

  1. System NetSuite
  2. Step Age the balance
  3. Step Suppression check
  4. Step Escalation ladder
  5. System Gmail
Also Slack Salesforce

Suppression is checked before every message, not once at the start, because the reason to stop usually appears mid-sequence.

The short answer

What is dunning automation?

Collections automation breaks into four parts: ageing at the customer level rather than per invoice, an escalation ladder that changes tone and channel as the debt gets older, suppression rules that stop the sequence the moment something changes, and a handoff to a person at the point where automation stops helping. The part that goes wrong most often is suppression. Dunning an account that has already paid, raised a dispute or is mid-renewal costs more than the invoice.

What matters here

  • Age at the customer level. Four invoices thirty days late is a different conversation from one invoice a hundred and twenty days late.
  • Check suppression before every message, not once at the start. Payments, disputes and renewals all appear mid-sequence.
  • Never dun an account in an active renewal or with an open escalation without the account owner knowing first.
  • Stop automating at the point a person is needed. A fifth automated email is not a collections strategy.
  • Measure days sales outstanding, not emails sent. The second number always goes up and means nothing.

Who this is for

You run credit control or finance operations. Chasing is manual, inconsistent, and the accounts that get chased are the ones somebody remembered rather than the ones costing the most.

How it works in practice

What has to happen between an invoice going overdue and the money arriving.

  1. 1

    Balances are aged per customer, not per invoice

    Because a customer with four small late invoices needs a different conversation from one with a single large one.

  2. 2

    Suppression is checked before every send

    Paid, disputed, in an active renewal, on a payment plan, or flagged by the account owner.

  3. 3

    Tone and channel escalate with age

    A gentle reminder, then a firmer one, then a call task, then a person. Not the same email four times.

  4. 4

    The account owner is told before anything firm goes out

    A commercial relationship is worth more than the invoice, and they may already know why it is late.

  5. 5

    A payment or a dispute stops the ladder immediately

    Not at the next scheduled run. Chasing somebody who paid yesterday is the fastest way to lose their goodwill.

  6. 6

    Automation hands over to a person at the end

    Past the last rung it is a human conversation, with everything already gathered.

What collections automation is made of

Four parts. The third is what keeps it from damaging the relationship.

Customer-level ageing

Total outstanding, oldest invoice, and the pattern across invoices. Per-invoice chasing sends four emails to one person on one morning.

An escalation ladder

Tone, channel and recipient changing with age, ending in a person rather than a fifth email.

Suppression rules

Paid, disputed, on a plan, in renewal, or held by the account owner. Checked before every send because the state changes mid-sequence.

A handoff

The point where automation stops and somebody calls, with the history and the balance already assembled.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Start here: find where the reasons to stop live

    Suppression state is scattered, and it is the part that protects the relationship.

    Headless skills build-workflow

    Use build-workflow. The systems in play are NetSuite and Salesforce,
    or whatever we run in those seats.
    
    I need invoices with due dates, payment state and any dispute flag, plus
    the customer record and payment terms. From Salesforce I need open
    opportunities, renewal dates and the account owner.
    
    Map where each of these lives: paid, disputed, on a payment plan, in an
    active renewal, and manually held. Those five are the reasons not to
    send, and none of them are in the same place.
  2. 2

    Age at the customer level

    Because a person receives the emails, not an invoice.

    Headless skills build-workflow

    Use build-workflow. Build ageing per customer, not per invoice:
    
      Total outstanding, and how much falls in each ageing bucket
      The oldest unpaid invoice and its age
      Count of overdue invoices
      Whether this customer is usually on time, which changes the tone
    
    Never send one email per overdue invoice. A customer with four late
    invoices should receive one message listing all four, not four messages
    in one morning, which reads as a system rather than a company.
  3. 3

    Build the ladder, and check suppression before every send

    The state that stops a message usually appears mid-sequence.

    Build the escalation ladder, with tone and channel changing by age:
    
      due plus 3     a gentle reminder to the billing contact, with the
                     invoice and a payment link attached
      due plus 14    a firmer reminder, copying the AP contact
      due plus 30    notify the account owner, then email the billing
                     contact referencing the terms
      due plus 45    a call task for credit control, no further automation
      due plus 60    handoff, with the full history assembled
    
    Before every single send, check suppression: paid, part paid since the
    last message, disputed, on a payment plan, in an active renewal, or held
    by the account owner.
    
    Check at send time. A customer who paid yesterday receiving today's chase
    is the most common and most damaging failure here.

    The account owner notification at 30 days matters more than the email that follows it. They often already know why it is late, and sometimes they are the reason.

  4. 4

    Protect the commercial relationship

    Because the invoice is worth less than the account.

    Headless skills tray-gotchas

    Use tray-gotchas, then add these guards:
    
    An account with a renewal inside the next quarter never gets past the
    second rung without the account owner approving it.
    
    An account with an open severity one support escalation is suppressed
    entirely until the escalation closes. Chasing somebody whose service is
    broken is indefensible.
    
    A disputed invoice leaves the ladder and goes to a dispute queue. It is
    not overdue, it is contested, and treating it as overdue makes the
    dispute worse.
    
    Partial payment resets the tone but not the age. Somebody paying
    something is engaging, and the message should acknowledge it.
  5. 5

    Measure days outstanding, not messages sent

    One of those numbers is the point and the other always rises.

    Report weekly:
    
      Days sales outstanding, trended, overall and by segment
      Total overdue by ageing bucket
      Promise-to-pay kept rate, where a customer said a date
      Suppression events by reason, which shows how often the ladder was
      about to do something it should not
      Escalations to a person, and what happened after
    
    Do not report emails sent as a success measure. It rises whether or not
    anybody pays, and optimising for it produces exactly the behaviour that
    damages accounts.
  6. 6

    Test it, then hand the ladder to credit control

    Because tone and timing are a commercial judgement.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production. Run it in preview for a fortnight first: compute what
    would send, send nothing, and have credit control read the list.
    
    Then open the same workflow in Tray Build so credit control can adjust
    the rungs, the tone and the suppression rules in the visual canvas.

What it connects to

The ledger holds the debt, the CRM holds the relationship, and both decide whether to send.

NetSuite

Read invoices, payments, credit notes and disputes. Write the collection status and any promise-to-pay date.

Reads and writes

Salesforce

Read open renewals, the account owner and any hold. Write the collection state so the account team is never surprised.

Reads and writes

Gmail

Send the reminders from a monitored address, so a reply reaches a person instead of a no-reply mailbox.

Reads and writes

Slack

Tell the account owner before anything firm goes out, and raise the handoff when automation ends.

Writes

Stripe

Read payment attempts and failures where collection runs on card, since a failed card is not the same as a refusal to pay.

Reads

Zendesk

Read open escalations, because chasing a customer whose service is broken is indefensible.

Reads

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, SAP S/4HANA, Microsoft Teams, Jira, Microsoft Outlook or HubSpot.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This sends money-related email to customers automatically. The failure mode is a damaged relationship.

It runs on the platform, not on somebody's machine

Daily ageing and send-time suppression checks run on the same engine, so a customer who paid overnight is never chased in the morning.

Every send and every suppression is recorded

What went out, to whom, and what stopped a message that would have gone. When an account complains, that is the answer.

No credential ever lands in the workflow itself

The mail credential can send as your finance team. It lives in your workspace, scoped to that address and revocable on its own.

Credit control owns the ladder

Rungs, tone and suppression rules open in Tray Build, adjusted by the team that owns the relationship with the debt.

Preview before it sends anything

A fortnight computing what would go out, sending nothing. The first read of that list always changes the rules.

Questions people ask

Why age at the customer level?

Because a person receives the messages. A customer with four overdue invoices should get one email listing all four, not four separate chases in one morning, which reads as a machine instead of a company.

Why check suppression before every send?

Because the reasons to stop appear mid-sequence. A payment, a dispute or a renewal opening between rung two and rung three all mean the next message should not go, and a check at enrolment cannot know that.

Should an account in renewal be chased?

Not past a gentle reminder without the account owner approving it. The renewal is worth more than the invoice, and the owner frequently knows why payment is late.

What about disputed invoices?

They leave the ladder entirely and go to a dispute queue. A contested invoice is not overdue, and chasing it as though it were makes the dispute harder to resolve.

What is the right metric for a collections programme?

Days sales outstanding and promise-to-pay kept rate. Not emails sent, which rises whether or not anybody pays and rewards exactly the behaviour that damages accounts.

Vibe-coding app guides

Vibe-code an entire app with Helix

This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.

How to build an order management tracker (opens helix.tray.ai in a new tab)

Last reviewed September 2026.