n8n Invoice Payment Chase Automation Project: Step-by-Step Tutorial
Automate overdue invoice reminders by scheduling daily checks of accounting spreadsheets, filtering overdue clients, and sending personalized chase emails.
The Problem
Automate overdue invoice reminders by scheduling daily checks of accounting spreadsheets, filtering overdue clients, and sending personalized chase emails.
Real-World Use Case
Automate overdue invoice reminders by scheduling daily checks of accounting spreadsheets, filtering overdue clients, and sending personalized chase emails.
Technology Stack
Familiarity with n8n Schedule trigger nodes
Prerequisite
Understanding of IF conditional nodes in n8n
Prerequisite
Connected Gmail or SMTP node credentials
Prerequisite
Architecture & Design
Folder Structure
n8n_workflows/
├── payment_chase.json
└── README.mdStep-by-Step Implementation
Configure Schedule trigger node to run every morning at 9:00 AM.
### Step 1: Schedule Trigger Setup Add Schedule trigger node. Configure cron expression for daily morning execution.
{
"name": "Overdue Invoice Payment Chase",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"sheetId": "spreadsheet_id_here"
},
"name": "Read Invoices",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "Overdue"
}
]
}
},
"name": "Check Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
640,
300
]
},
{
"parameters": {
"recipient": "={{ $json.client_email }}",
"subject": "Overdue Invoice Reminder - #{{ $json.invoice_id }}",
"body": "Hi {{ $json.client_name }},\n\nThis is a reminder that invoice #{{ $json.invoice_id }} for ${{ $json.amount }} is overdue. Please arrange payment.\n\nThank you!"
},
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
880,
200
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Read Invoices",
"type": "main",
"index": 0
}
]
]
},
"Read Invoices": {
"main": [
[
{
"node": "Check Overdue",
"type": "main",
"index": 0
}
]
]
},
"Check Overdue": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
]
]
}
}
}Code Explanation
Implementation step
Fetch invoice records from Google Sheets.
### Step 2: Data Fetching & Filter Logic Add Google Sheets node to read rows, then add IF node evaluating status.
{
"name": "Overdue Invoice Payment Chase",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"sheetId": "spreadsheet_id_here"
},
"name": "Read Invoices",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "Overdue"
}
]
}
},
"name": "Check Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
640,
300
]
},
{
"parameters": {
"recipient": "={{ $json.client_email }}",
"subject": "Overdue Invoice Reminder - #{{ $json.invoice_id }}",
"body": "Hi {{ $json.client_name }},\n\nThis is a reminder that invoice #{{ $json.invoice_id }} for ${{ $json.amount }} is overdue. Please arrange payment.\n\nThank you!"
},
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
880,
200
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Read Invoices",
"type": "main",
"index": 0
}
]
]
},
"Read Invoices": {
"main": [
[
{
"node": "Check Overdue",
"type": "main",
"index": 0
}
]
]
},
"Check Overdue": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
]
]
}
}
}Code Explanation
Implementation step
Add IF node checking if due date is in the past and payment status is 'Unpaid'.
### Step 3: Email Action Add Gmail node. Map client name and invoice amount into email body.
{
"name": "Overdue Invoice Payment Chase",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"sheetId": "spreadsheet_id_here"
},
"name": "Read Invoices",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "Overdue"
}
]
}
},
"name": "Check Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
640,
300
]
},
{
"parameters": {
"recipient": "={{ $json.client_email }}",
"subject": "Overdue Invoice Reminder - #{{ $json.invoice_id }}",
"body": "Hi {{ $json.client_name }},\n\nThis is a reminder that invoice #{{ $json.invoice_id }} for ${{ $json.amount }} is overdue. Please arrange payment.\n\nThank you!"
},
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
880,
200
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Read Invoices",
"type": "main",
"index": 0
}
]
]
},
"Read Invoices": {
"main": [
[
{
"node": "Check Overdue",
"type": "main",
"index": 0
}
]
]
},
"Check Overdue": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
]
]
}
}
}Code Explanation
Implementation step
Route true matches to Gmail node sending reminder template.
### Step 4: Edge Cases Add error handling to ensure failing email sends don't crash subsequent row processing.
{
"name": "Overdue Invoice Payment Chase",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"sheetId": "spreadsheet_id_here"
},
"name": "Read Invoices",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "Overdue"
}
]
}
},
"name": "Check Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
640,
300
]
},
{
"parameters": {
"recipient": "={{ $json.client_email }}",
"subject": "Overdue Invoice Reminder - #{{ $json.invoice_id }}",
"body": "Hi {{ $json.client_name }},\n\nThis is a reminder that invoice #{{ $json.invoice_id }} for ${{ $json.amount }} is overdue. Please arrange payment.\n\nThank you!"
},
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
880,
200
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Read Invoices",
"type": "main",
"index": 0
}
]
]
},
"Read Invoices": {
"main": [
[
{
"node": "Check Overdue",
"type": "main",
"index": 0
}
]
]
},
"Check Overdue": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
]
]
}
}
}Code Explanation
Implementation step
Route false matches to no-op termination.
### Step 4: Edge Cases Add error handling to ensure failing email sends don't crash subsequent row processing.
{
"name": "Overdue Invoice Payment Chase",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
200,
300
]
},
{
"parameters": {
"operation": "read",
"sheetId": "spreadsheet_id_here"
},
"name": "Read Invoices",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 2,
"position": [
420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"value2": "Overdue"
}
]
}
},
"name": "Check Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
640,
300
]
},
{
"parameters": {
"recipient": "={{ $json.client_email }}",
"subject": "Overdue Invoice Reminder - #{{ $json.invoice_id }}",
"body": "Hi {{ $json.client_name }},\n\nThis is a reminder that invoice #{{ $json.invoice_id }} for ${{ $json.amount }} is overdue. Please arrange payment.\n\nThank you!"
},
"name": "Send Gmail",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
880,
200
]
}
],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Read Invoices",
"type": "main",
"index": 0
}
]
]
},
"Read Invoices": {
"main": [
[
{
"node": "Check Overdue",
"type": "main",
"index": 0
}
]
]
},
"Check Overdue": {
"main": [
[
{
"node": "Send Gmail",
"type": "main",
"index": 0
}
]
]
}
}
}Code Explanation
Implementation step
Common Errors
Ensure spreadsheet dates match n8n ISO evaluation format.
Security & Performance
Click Execute Workflow manually to verify spreadsheet parsing.
Check that emails are sent only to overdue records.
Send SMS notification via Twilio node.
Update CRM status to 'Chasing' upon email send.
Interview Questions
Q: Can I customize email text per client?
A: Yes, using n8n expressions to inject client names and amounts dynamically.