AutomationFlowsFinance › Automate Xero Invoices and Payments Using Webhooks, Postgresql and Whatsapp

Automate Xero Invoices and Payments Using Webhooks, Postgresql and Whatsapp

ByGilbert Onyebuchi @gilbert-onyebuchi on n8n.io

This workflow automates the full invoicing and payment process using n8n and Xero. It allows businesses to generate invoices, track payments, send WhatsApp notifications, and keep records synced automatically, without manual follow-ups or repetitive admin work.

Webhook trigger★★★★☆ complexity17 nodesXeroGoogle CalendarTwilioPostgres
Finance Trigger: Webhook Nodes: 17 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #12695 — we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "46e661c8-a327-49d0-87e0-1f04332719eb",
      "name": "Webhook Trigger - Invoice Created",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -976,
        160
      ],
      "parameters": {
        "path": "225363a4-5e45-46b5-aefe-8ca0a4fa27b2",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 1.1
    },
    {
      "id": "46877753-f483-4723-b94c-ef44eb4d4ec4",
      "name": "Webhook - Payment Received",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -848,
        624
      ],
      "parameters": {
        "path": "1f435bd2-cbfe-4c4d-9cbd-cc3bf4f8e10a",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 1.1
    },
    {
      "id": "fc186c16-7e9b-4a82-be6d-f80cdbc5970b",
      "name": "Xero - Create Invoice",
      "type": "n8n-nodes-base.xero",
      "position": [
        -752,
        160
      ],
      "parameters": {
        "type": "ACCREC",
        "contactId": "Your_Contact_ID",
        "lineItemsUi": {
          "lineItemsValues": [
            {
              "taxType": "OUTPUT",
              "itemCode": "=",
              "quantity": "={{ $json.body.lineItems[0].quantity }}",
              "taxAmount": "={{ $json.body.totalAmount * 0.007 }}",
              "lineAmount": "={{ $json.body.totalAmount }}",
              "unitAmount": "={{ $json.body.lineItems[0].unitAmount }}",
              "accountCode": "200",
              "description": "={{ $json.body.lineItems[0].description }}"
            }
          ]
        },
        "organizationId": "a5917db9-07f1-40dc-b5f6-c55b39730d0f",
        "additionalFields": {
          "status": "AUTHORISED",
          "dueDate": "={{ $json.body.dueDate }}",
          "reference": "={{ $json.body.reference }}",
          "invoiceNumber": "={{ $json.body.invoiceNumber }}"
        }
      },
      "credentials": {
        "xeroOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "28cd7036-ad73-4808-9358-d286a30aa713",
      "name": "IF - Invoice Created Successfully",
      "type": "n8n-nodes-base.if",
      "position": [
        -528,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.Status }}",
              "rightValue": "AUTHORISED"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3defccf8-8d1e-4090-a66e-a42ec8ebfd0c",
      "name": "Google Calendar - Create Due Date Event",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        -80,
        64
      ],
      "parameters": {
        "end": "={{ $json[\"Due Date\"] }}T10:00:00",
        "start": "={{ $json[\"Due Date\"] }}T09:00:00",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "user@example.com"
        },
        "additionalFields": {
          "sendUpdates": "all"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "91bec07f-240b-4a65-a99e-84e3c4a5a6fd",
      "name": "WhatsApp - Send Invoice Confirmation",
      "type": "n8n-nodes-base.twilio",
      "position": [
        144,
        64
      ],
      "parameters": {
        "to": "Recipient_number",
        "from": "Your_number",
        "message": "=Hello {{ $('IF - Invoice Created Successfully').item.json.Contact.Name }},\n\nYour invoice #{{ $('IF - Invoice Created Successfully').item.json.InvoiceNumber }} for {{  $('IF - Invoice Created Successfully').item.json.Total }} has been created.\n\n\ud83d\udcc4 Due Date: {{ $('IF - Invoice Created Successfully').item.json.DueDateString }}\n\ud83d\udcb3 Amount: {{ $('IF - Invoice Created Successfully').item.json.Total }}\n\nPlease ensure payment is made by the due date.\n\nThank you!",
        "options": {},
        "toWhatsapp": true
      },
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dc9f2c38-1ea9-4023-aaac-83e1fe0d576b",
      "name": "Respond to Webhook - Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        368,
        64
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": true, \"message\": \"Invoice created and notifications sent\", \"invoiceId\": $json.invoiceId } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "80970a52-22ab-45a2-b12a-09787ab1b3a4",
      "name": "Respond to Webhook - Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -304,
        256
      ],
      "parameters": {
        "options": {
          "responseCode": 500
        },
        "respondWith": "json",
        "responseBody": "={{ { \"success\": false, \"message\": \"Invoice creation failed\", \"error\": $json.error } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "66eec00c-c906-4ce7-af0d-663627a35026",
      "name": "Google Calendar - Remove Due Date Event",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        48,
        624
      ],
      "parameters": {
        "eventId": "={{ $json.calendarEventId }}",
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "user@example.com"
        },
        "operation": "delete"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d590ac64-9726-4281-b623-d0c3f067000e",
      "name": "Respond to Webhook - Payment",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        272,
        624
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": true, \"message\": \"Payment processed successfully\" } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "5a9bef7d-00d0-4445-838d-22c4b775709d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1120,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 1712,
        "height": 480,
        "content": "## 1. Create invoice, send notification and log"
      },
      "typeVersion": 1
    },
    {
      "id": "ae217e1c-558d-478e-b306-2d7018c6e191",
      "name": "Xero - Update Invoice to Paid1",
      "type": "n8n-nodes-base.xero",
      "position": [
        -432,
        624
      ],
      "parameters": {
        "invoiceId": "={{ $json.body.invoiceId }}",
        "operation": "update",
        "updateFields": {},
        "organizationId": "a5917db9-07f1-40dc-b5f6-c55b39730d0f"
      },
      "credentials": {
        "xeroOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bfbf6c28-9698-44f7-83ea-136decf182b7",
      "name": "WhatsApp - Send Invoice Confirmation1",
      "type": "n8n-nodes-base.twilio",
      "position": [
        -192,
        624
      ],
      "parameters": {
        "to": "Recipient_number",
        "from": "Your_number",
        "message": "=Hello {{ $json.clientName }},\n\n\u2705 Payment Received!\n\nWe have received your payment of {{ $json.paymentAmount }} for Invoice #{{ $json.invoiceNumber }}.\n\n\ud83c\udf89 Thank you for your prompt payment!\n\nTransaction ID: {{ $json.transactionId }}",
        "options": {},
        "toWhatsapp": true
      },
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d6f9e06a-b35e-4491-8144-9f25742d3c61",
      "name": "Add Invoice Record",
      "type": "n8n-nodes-base.postgres",
      "notes": "Optional: Enable if using PostgreSQL for logging",
      "position": [
        -288,
        64
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "invoice_logs",
          "cachedResultName": "invoice_logs"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "id": 0,
            "Amount": "={{ $json.AmountDue }}",
            "Status": "={{ $json.Contact.ContactStatus }}",
            "Due Date": "={{ $json.Date }}",
            "timestamp": "={{ $json.DateString }}",
            "invoice_id": "={{ $json.InvoiceID }}",
            "Client Name": "={{ $json.Contact.Name }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Client Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_id",
              "type": "string",
              "display": true,
              "required": true,
              "displayName": "invoice_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Created Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Reminders Sent",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Payment Reminders Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Reminder Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Last Reminder Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Payment Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Client Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Client Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "91b4f81e-35dd-42ee-892b-129e1aad06dd",
      "name": "PostgreSQL - Update Payment Status",
      "type": "n8n-nodes-base.postgres",
      "notes": "Optional: Enable if using PostgreSQL for logging",
      "position": [
        -640,
        624
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "invoice_logs",
          "cachedResultName": "invoice_logs"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "id": 0,
            "invoice_id": "{{ $json.body.invoiceId }}",
            "Payment Date": "={{ $json.body.paymentDate }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Client Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Due Date",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Due Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoice_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": true,
              "displayName": "invoice_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Created Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Reminders Sent",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Payment Reminders Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Reminder Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Last Reminder Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Payment Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Client Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Client Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id",
            "invoice_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "92e31fcd-2448-46bd-8691-6d080d3ea60d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1024,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 1552,
        "height": 336,
        "content": "## 2. Check and update payments, send notification and cancel event"
      },
      "typeVersion": 1
    },
    {
      "id": "090248e1-88ab-4977-b046-6065a3e683c9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1728,
        -32
      ],
      "parameters": {
        "width": 480,
        "height": 624,
        "content": "## Xero Invoice and Payment Automation Using n8n, PostgreSQL, and WhatsApp\n\n## How it works\n- **Webhook Trigger nodes** call the data from the source\n- **Xero nodes** are used to create and update invoices\n- **If node** to verify if invoice is successfully created\n- **PostgreSQL nodes serve as a database to log invoice records and update\n- Google Calendar nodes** are to log and modify the calendar event\n- **Twilio nodes** are to send WhatsApp notifications\n- **Respond webhook nodes** to send webhook responses\n\n## Setup\n1. Go to [xero](https://www.xero.com/), create an App, get details and add to credentials, then match\n2. Go to [Supabase](https://supabase.com/), create a table with the required details, connect and add to PostgreSQL credentials. P.S. This is not a mistake\n3. Enable Google Calendar from [Google Cloud console](https://console.cloud.google.com/) and connect to credentials\n4. Go to [Twilio](https://www.twilio.com/en-us) and connect to n8n credential. Get your WhatsApp number there, too\n5. Match the webhook to the payment data source and match the data in the nodes"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Add Invoice Record": {
      "main": [
        [
          {
            "node": "Google Calendar - Create Due Date Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Xero - Create Invoice": {
      "main": [
        [
          {
            "node": "IF - Invoice Created Successfully",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - Payment Received": {
      "main": [
        [
          {
            "node": "PostgreSQL - Update Payment Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Xero - Update Invoice to Paid1": {
      "main": [
        [
          {
            "node": "WhatsApp - Send Invoice Confirmation1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF - Invoice Created Successfully": {
      "main": [
        [
          {
            "node": "Add Invoice Record",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook - Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger - Invoice Created": {
      "main": [
        [
          {
            "node": "Xero - Create Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PostgreSQL - Update Payment Status": {
      "main": [
        [
          {
            "node": "Xero - Update Invoice to Paid1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp - Send Invoice Confirmation": {
      "main": [
        [
          {
            "node": "Respond to Webhook - Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp - Send Invoice Confirmation1": {
      "main": [
        [
          {
            "node": "Google Calendar - Remove Due Date Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Calendar - Create Due Date Event": {
      "main": [
        [
          {
            "node": "WhatsApp - Send Invoice Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Calendar - Remove Due Date Event": {
      "main": [
        [
          {
            "node": "Respond to Webhook - Payment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automates the full invoicing and payment process using n8n and Xero. It allows businesses to generate invoices, track payments, send WhatsApp notifications, and keep records synced automatically, without manual follow-ups or repetitive admin work.

Source: https://n8n.io/workflows/12695/ — original creator credit. Request a take-down →

More Finance workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Finance

AP Invoice — 01 Orchestrator. Uses postgres, httpRequest, quickbooks, slack. Webhook trigger; 42 nodes.

Postgres, HTTP Request, QuickBooks +1
Finance

How It Works Trigger: Watches for new emails in Gmail with PDF/image attachments. OCR: Sends the attachment to OCR.space API (https://ocr.space/OCRAPI) to extract invoice text. Parsing: Extracts key f

Gmail Trigger, Google Sheets, Slack +3
Finance

This workflow automates the entire process of receiving a product/service order, checking or creating a customer in QuickBooks Online (QBO), generating an invoice, and emailing it — all triggered by a

QuickBooks
Finance

Tired of the standard, boring invoices from QuickBooks Online? This workflow completely automates the process of creating beautiful, custom-branded PDF invoices and emailing them directly to your clie

QuickBooks, HTTP Request, Email Send
Finance

Automated QuickBooks Invoice to Custom PDF & Email

QuickBooks, HTTP Request, Email Send