BadCop

The polite-but-firm invoice chaser.
You stay the good cop.

BadCop sends an escalating ladder of payment reminders from a separate accounts@ address, applies the late fee your contract already allows, and stops the moment the money lands. Free, open source, zero dependencies.

Get it on GitHub Just want the email templates?
$ badcop run --dry-run
DRY RUN INV-1001 -> ap@acme.example [firm, +7d]
  Subject: Overdue: invoice INV-1001 (7 days past due)
DRY RUN INV-1002 -> hello@bluefern.example [courtesy, -3d]
  Subject: Invoice INV-1002 is due on 2026-09-11
2 would be sent

Why it exists

A freelancer on r/smallbusiness added up their year and found $3,200 in late and unpaid invoices. Not because clients were crooks, but because sending the firm email felt rude, so it went out on day 10 instead of day 1, and the late fee in the contract was never enforced. They asked for a "bad cop". This is it.

The ladder

Every step is sent exactly once per invoice. If the client pays after the friendly reminder, nothing else goes out. If they don't, the tone escalates on a fixed schedule so you never have to decide whether today is the day.

How it works

  1. Keep a CSV of your invoices. Export it from Wave, FreshBooks, QuickBooks, Stripe or whatever you use, or type it in.
  2. Run badcop run once a day with cron, a systemd timer or Docker. Or skip the server entirely: the template repository runs it every morning on GitHub Actions for free.
  3. Export a bank CSV when money comes in. badcop match bank.csv --apply closes the matching invoices.
  4. badcop report tells you what is outstanding, how old it is, and what it is costing your clients.

Install

pip install badcop
badcop init          # sample config, ledger and templates
badcop run --dry-run # read every email before anything is sent

Python 3.11 or newer. Nothing else. Full documentation on GitHub. Don't want to run anything? Use the template: a private repo that runs the ladder daily on GitHub Actions, with your invoices in a CSV or a Google Sheet.

Free resources

Courtesy payment reminder email (3 days before the due date)Before dueFriendly invoice reminder email (1 day overdue)1 days overdueFirm invoice reminder email (7 days overdue)7 days overdueFinal notice invoice email with late fee (14 days overdue)14 days overdueInvoice 30 days overdue: the escalation email30 days overdueSecond payment reminder email (after the first was ignored)7 days overduePolite payment reminder email that still gets results1 days overduePayment reminder text message (SMS) template3 days overdueInvoice 60 days overdue: demand letter before collections or small claims60 days overdueInvoice reminder email for recurring (retainer) clientsBefore dueInvoice reminder email subject lines that get opened7 days overdueLate fee applied email template14 days overdue Late-fee calculatorWhat an overdue invoice is costing, by day Reminder schedulesLadders for net 7 to net 60 terms Late fees by countryUK, EU, US, Germany, Ireland, Australia, Canada, NZ How to chase unpaid invoicesThe full playbook, no tool required

Questions

Will this annoy my clients?

The default copy is courteous through the firm step and factual in the final notice. Nothing threatens; the last step goes to you, not to the client. You can preview and rewrite every email before anything is sent.

Can I charge late fees?

Only if your contract or invoice terms say so. BadCop applies whatever percentage and grace period you enter and nothing else. Set it to zero if you have no such terms.

Does it send invoices?

No. It chases the ones you already sent, from whatever tool you use. Keep invoicing the way you do.

Does it need my bank login?

No. Payment matching reads a CSV you export from your bank or payment processor.

What does it cost?

The command-line tool is free and open source (MIT). A hosted version that runs it for you is planned; the CLI will stay free.