# Triage a draft invoice queue after a billing cutover

> Move a billing cycle and some clients will get two invoices in a week. Sort the draft queue into four buckets using the gap since each client's last send and whether they paid it, then attach a short timing note only to the invoices that need one. Sending all of them identically is what triggers the "haven't I just paid this?" call.

URL: https://biloh.com.au/docs/how-to/triage-invoices-after-a-billing-cutover
Category: How-to guides | Audience: operator | Updated: 2026-08-28

## The problem cutovers create

A business that has always invoiced monthly in arrears gives its clients roughly a month between invoices. Move that business onto per-job invoicing — where a completed job drafts its own invoice — and the old and new rhythms collide exactly once.

The last month-in-arrears invoice goes out late, because migrating took time. Then the first job of the new month completes, and the platform drafts an invoice immediately. The client receives a second invoice one to four days after paying the first.

Nothing is wrong with either invoice. They cover different work. But the client's inbox tells a different story, and the call you get is *"I've just paid you."*

The fix is not to delay the invoices. It is to **sort the queue before you send**, and let each invoice carry the explanation it actually needs.

## Sort the queue by evidence, not by feel

Pull every draft with `list_invoices(status: "draft")`. For each one, get the client's own invoice history with `list_client_invoices(client_id)`.

Two facts decide the bucket:

1. **The gap** — days between the previous invoice's `sent_at` and this draft. Note `sent_at`, not `issued_at`. An invoice issued in July but emailed in August lands in the client's inbox in August, and the inbox is what they react to.
2. **Whether that previous invoice is paid.** A client who just paid needs reassurance. A client who hasn't needs something else entirely.

| Bucket | Test | Treatment |
|---|---|---|
| **A — close behind** | previous invoice sent within about a week **and** paid | Send with a short timing note |
| **B — first invoice ever** | no previous invoice for this client | Welcome note. **No** timing note |
| **C — normal spacing** | previous invoice sent more than a month ago | Send plain |
| **D — blocked** | a data problem surfaced at preview | Fix before sending |

Bucket B matters more than it looks. A brand-new client who receives "your July invoice went out late" has no idea what you're talking about — you have just made a clean first impression confusing. Buckets are about who needs which explanation, not about being thorough.

## Write the note once, vary it slightly

Personalise the send with `update_pending_send(cover_message)` after staging and before approving. See [Personalise a staged send](/docs/how-to/personalise-a-staged-send) for how the slot renders.

A note that works has four moves in it:

1. **Name the cause without drama.** "Your last invoice only went out at the start of the month while we were moving across to a new system."
2. **Say the thing they're actually worried about, in your own words.** "Nothing has doubled up — the last invoice covered the previous visit, and this one covers this month's."
3. **Promise the rhythm returns.** "From here it settles back to the normal monthly spacing." This is the sentence that stops them wondering whether it happens every month.
4. **Thank them for the payment they just made.** They did the right thing quickly; say so.

Vary only the site or service reference between clients. Resist rewriting the whole note per client — consistency is not impersonal here, and four hand-written variants is four chances to say something you did not mean.

## What "blocked" looks like

Preview is where data problems surface, because the preview shows you the resolved recipient rather than the record you assumed was there. Things worth stopping for:

- **The billing email is not the client's.** During a migration it is common to find a placeholder — often the operator's own address — sitting in `billing_email`. The send will succeed and reach nobody who matters.
- **The client record is still a lead.** Invoicing works, but reporting and portal access will behave oddly later.
- **Terms are due-on-receipt when they shouldn't be.** The invoice renders with a due date equal to its issue date, so it arrives already due. That reads as aggressive when the real cause is an unset field.

Fix the record, then send. Do not send and fix afterwards — the client already has the email.

## Verify at the end, not per invoice

When the run is finished, call `list_invoices(status: "draft")` again. An empty result is the assertion that matters: every draft was dealt with, not skipped. Then spot-check that anything you settled outside the email path reads `status: "paid"` and `outstanding_cents: 0`.

## Do it once, then make it structural

Timing notes are a one-off remedy for a one-off collision. The durable fix is the client's invoicing cadence — per job on completion, consolidated for the period, or on the period's last job. Set that deliberately per client during onboarding and the collision never recurs.

## Related

- [Personalise a staged send](/docs/how-to/personalise-a-staged-send)
- [Invoice send gates and guards](/docs/reference/invoice-send-gates-and-guards)
