How to Build an Automated Invoice Reminder System Without Hiring Anyone
Set up an invoice reminder workflow using AI and no-code tools that chases late payments for you, around the clock, without a collections team.
How to Build an Automated Invoice Reminder System Without Hiring Anyone
Late invoices are one of the most common cash-flow killers for small businesses and solopreneurs. Chasing payments by hand takes time you do not have, and hiring someone to do it is expensive. This tutorial walks you through building a fully automated invoice reminder system using n8n, an AI writing step, and your existing email provider. Once it is live, it runs without you.
What You Will Build
A workflow that:
- Reads unpaid invoices from your accounting tool (we use Wave, but QuickBooks or FreshBooks work the same way)
- Calculates how many days overdue each invoice is
- Uses an AI prompt to write a tone-matched reminder (polite at 7 days, firmer at 14, urgent at 30)
- Sends the email from your own address
- Logs each reminder to a Google Sheet so you have a paper trail
Total setup time: about 90 minutes. Zero recurring cost if you stay within free-tier limits.
Prerequisites
Before you start, make sure you have:
- An n8n account (cloud or self-hosted)
- A Wave, QuickBooks, or FreshBooks account with at least one open invoice
- An OpenAI API key (GPT-4o mini is cheap enough that a month of reminders costs under $1)
- A Gmail account or SMTP credentials for any other email provider
- A Google Sheet to log reminders (create a blank one now and name the first sheet "Log")
Step 1: Pull Unpaid Invoices from Your Accounting Tool
Open n8n and create a new workflow. Add a Schedule Trigger node. Set it to run every day at 9:00 AM in your timezone. This is the heartbeat of the system.
Next, add an HTTP Request node. This node will call your accounting tool's API.
For Wave:
- Method:
GET - URL:
https://gql.waveapps.com/graphql/public - Authentication: Bearer token (paste your Wave API token)
- Body type: GraphQL
Use this query to fetch invoices that are due but unpaid:
query {
business(id: "YOUR_BUSINESS_ID") {
invoices(page: 1, pageSize: 50, invoiceStatus: SAVED) {
edges {
node {
id
invoiceNumber
dueDate
amountDue { value currency { symbol } }
customer { name email }
}
}
}
}
}
Replace YOUR_BUSINESS_ID with the ID from your Wave URL.
If you use QuickBooks, the equivalent endpoint is GET /v3/company/{realmId}/query?query=SELECT * FROM Invoice WHERE Balance > '0'.
Step 2: Filter and Calculate Days Overdue
Add a Code node after your HTTP Request. This step filters out invoices that are not yet past due and calculates how many days late each one is.
const today = new Date();
const items = $input.all();
const overdueInvoices = [];
for (const item of items) {
const invoice = item.json;
const dueDate = new Date(invoice.dueDate);
const diffMs = today - dueDate;
const daysOverdue = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (daysOverdue > 0) {
overdueInvoices.push({
json: {
...invoice,
daysOverdue,
}
});
}
}
return overdueInvoices;
This outputs one item per overdue invoice, each enriched with a daysOverdue field. Invoices due today or in the future are dropped.
Step 3: Write Tone-Matched Reminders with AI
Add an OpenAI node (or an HTTP Request node pointed at https://api.openai.com/v1/chat/completions). Set model to gpt-4o-mini.
In the system message, set the tone rules:
You write invoice payment reminders on behalf of a small business owner.
- If daysOverdue is 1 to 10: be polite and assume the payment slipped through.
- If daysOverdue is 11 to 21: be professional and direct. Mention the specific amount.
- If daysOverdue is 22 or more: be firm. State that the account is significantly overdue and ask for immediate action or a payment plan.
Never be rude. Never threaten legal action. Keep the email under 120 words. No subject line, just body text.
In the user message, pass invoice data using n8n expressions:
Write a payment reminder for:
Customer: {{ $json.customer.name }}
Invoice number: {{ $json.invoiceNumber }}
Amount due: {{ $json.amountDue.currency.symbol }}{{ $json.amountDue.value }}
Days overdue: {{ $json.daysOverdue }}
The model will return a short, appropriately toned email body for each invoice.
Step 4: Send the Email
Add a Gmail node (or Send Email node for SMTP). Configure it as follows:
- To:
{{ $json.customer.email }} - From: your business email address
- Subject:
Invoice #{{ $json.invoiceNumber }} — Payment Due - Body: the AI-generated text from the previous step (
{{ $('OpenAI').item.json.choices[0].message.content }})
Connect your Gmail OAuth credential. If you use a custom domain, use the SMTP node with your mail server settings instead.
At this point, the workflow is functional. Run it once in test mode using a real overdue invoice to confirm the email looks right before enabling the schedule.
Step 5: Log Every Reminder to Google Sheets
Add a Google Sheets node after the email step. Set it to Append Row. Select your log sheet.
Map these columns:
| Column | Value |
|--------|-------|
| Date Sent | {{ $now.toISO() }} |
| Customer | {{ $json.customer.name }} |
| Invoice | {{ $json.invoiceNumber }} |
| Amount | {{ $json.amountDue.value }} |
| Days Overdue | {{ $json.daysOverdue }} |
| Email Sent To | {{ $json.customer.email }} |
This log gives you a record if a customer ever disputes receiving a reminder, and it helps you spot chronic late payers over time.
Step 6: Add a Stop Condition So You Do Not Spam Paid Clients
There is one important edge case: your accounting tool's API may return invoices that were paid after your workflow last ran but before it synced. Add an IF node between the filter step and the AI step.
Set the condition to check that daysOverdue is greater than 0 AND less than 60. Invoices more than 60 days overdue likely need a personal touch, and you should handle those yourself rather than sending automated emails indefinitely.
You can also add a check against your Google Sheet log. Add a Google Sheets node before the AI step that searches for any row matching the current invoice number. If a reminder was sent in the last 7 days, skip to the next invoice using an IF node that routes to a No Operation node.
Step 7: Activate and Monitor
Once you have tested the workflow end-to-end with at least two invoices, activate it. The schedule trigger will handle the rest.
To monitor it:
- Check the n8n execution log once a week for any failed runs
- Review your Google Sheet log monthly to identify customers who consistently pay late
- Adjust the tone thresholds in the AI system prompt if you find the messages are too harsh or too soft
Extending the System
Once the base workflow is running, there are a few natural upgrades:
Add SMS reminders. Connect a Twilio node after the email step. For invoices over 30 days, send a short SMS in addition to the email. This roughly doubles response rates on seriously overdue invoices.
Route to a Slack channel. Add a Slack node that posts a summary each morning listing which reminders were sent and the total outstanding amount. This gives you financial visibility without logging into your accounting tool.
Auto-pause on payment. Set up a second workflow triggered by a webhook from your accounting tool. When an invoice is marked paid, the webhook fires and adds the invoice number to a "paid" list in Google Sheets. The main workflow checks this list before sending any reminder.
What This Replaces
Before this workflow, following up on late invoices meant either doing it yourself (time you do not have), outsourcing it (cost you do not want), or just letting late payments slide (revenue you cannot afford to lose). This system does the follow-up for you, at the right tone, at the right interval, without anyone on payroll.
The total API cost for a business with 50 active invoices is roughly $0.50 per month. The time cost after setup is about 5 minutes a month to glance at the log.
That is the core value proposition of building without employees: you invest time once to design the system, and then the system runs indefinitely on your behalf.