This workflow corresponds to n8n.io template #15188 — we link there as the canonical source.
This workflow follows the HTTP Request → Slack recipe pattern — see all workflows that pair these two integrations.
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 →
{
"name": "Track Pennylane invoice payment status with Slack notifications",
"nodes": [
{
"id": "6ea2a45d-df0a-4ec7-a38e-740c40782606",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-784,
-272
],
"parameters": {
"width": 640,
"height": 1024,
"content": "# Track Pennylane invoice payment status with Slack notifications\n\n## Who is this for\n\nTeams using Pennylane who want automatic alerts when invoices are paid or become overdue, without checking Pennylane manually.\n\n## What it does\n\nThis workflow runs every 15 minutes, fetches all customer invoices from Pennylane, and classifies them as paid, overdue, or upcoming. If any invoices have been paid or are overdue, it sends a summary notification to Slack. If everything is normal, the workflow ends silently.\n\n## How to set up\n\n1. Import this workflow into n8n\n2. Create a Header Auth credential: name `Authorization`, value `Bearer <YOUR_PENNYLANE_TOKEN>`\n3. Select your Slack channel in the SL Send Notification node\n4. Adjust the schedule interval in the Schedule Trigger node if needed\n\n## Requirements\n\n- Pennylane account with API access (Essentiel plan or higher)\n- Pennylane API token with scope: customer_invoices:all\n- (Optional) Slack workspace\n\nNote: Pennylane API does not support filtering by status or paid fields. All classification is done client-side in a Code node.\n\nPart of a 3-workflow billing suite: https://github.com/Gauthier-Huguenin/n8n-pennylane-auto-invoicing\n\n---\n\n### Flow\n\n`Schedule Trigger`\n \u2192 `PL Fetch Invoices`\n \u2192 `Code Filter Status Changes`\n \u2192 `IF Has Updates`\n \u2192 \u2705 `Code Build Payment Notification` \u2192 `SL Send Notification`\n \u2192 \u274c `Set Done`\n\n---\n\n### Node refs for $()\n\n- Schedule Trigger\n- PL Fetch Invoices\n- Code Filter Status Changes\n- IF Has Updates\n- Code Build Payment Notification\n- SL Send Notification\n- Set Done"
},
"typeVersion": 1
},
{
"id": "d45398dc-a8b8-4c63-a872-ea829ecfc92c",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-16,
32
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"typeVersion": 1.3
},
{
"id": "3472cf87-8215-4bd0-9e6d-fa78ecaed39a",
"name": "PL Fetch Invoices",
"type": "n8n-nodes-base.httpRequest",
"position": [
256,
32
],
"parameters": {
"url": "https://app.pennylane.com/api/external/v2/customer_invoices",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": []
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "d2b7e251-96c3-4228-b08c-2c147dcda8b7",
"name": "Code Filter Status Changes",
"type": "n8n-nodes-base.code",
"position": [
496,
32
],
"parameters": {
"jsCode": "// Refs: 'PL Fetch Invoices'\nconst invoices = $input.first().json.items;\nconst today = new Date().toISOString().split('T')[0];\n\nconst results = {\n paid: [],\n overdue: [],\n upcoming: []\n};\n\nfor (const inv of invoices) {\n if (inv.draft) continue;\n\n if (inv.paid) {\n results.paid.push(inv);\n } else if (inv.deadline < today) {\n results.overdue.push(inv);\n } else {\n results.upcoming.push(inv);\n }\n}\n\nreturn [{\n json: {\n total_invoices: invoices.length,\n paid_count: results.paid.length,\n overdue_count: results.overdue.length,\n upcoming_count: results.upcoming.length,\n paid: results.paid,\n overdue: results.overdue,\n has_updates: results.paid.length > 0 || results.overdue.length > 0\n }\n}];"
},
"typeVersion": 2
},
{
"id": "023f3a34-1a30-4ab2-b8f4-14227dac655c",
"name": "IF Has Updates",
"type": "n8n-nodes-base.if",
"position": [
672,
32
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "f6d3fe78-bb28-4193-b4c0-7d04e963d48f",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.has_updates }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "ac4d9578-3a5b-43cc-ab0a-8673987a377a",
"name": "Set Done",
"type": "n8n-nodes-base.set",
"position": [
1504,
48
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "aee99e96-e05f-4770-b8c4-53a574358d7b",
"name": "Status",
"type": "string",
"value": "no updates"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "66da8691-e7a6-4c3d-92f6-701fa2fdcc18",
"name": "Code Build Payment Notification",
"type": "n8n-nodes-base.code",
"position": [
912,
-48
],
"parameters": {
"jsCode": "// Refs: 'Code Filter Status Changes'\nconst data = $input.first().json;\nconst lines = ['\ud83d\udcca Pennylane Invoice Status Report', ''];\n\nif (data.paid_count > 0) {\n lines.push(`\u2705 ${data.paid_count} invoice(s) paid:`);\n for (const inv of data.paid) {\n lines.push(` - ${inv.invoice_number} | ${inv.currency_amount} ${inv.currency} | ${inv.label}`);\n }\n lines.push('');\n}\n\nif (data.overdue_count > 0) {\n lines.push(`\u26a0\ufe0f ${data.overdue_count} invoice(s) overdue:`);\n for (const inv of data.overdue) {\n lines.push(` - ${inv.invoice_number} | ${inv.currency_amount} ${inv.currency} | Due: ${inv.deadline} | ${inv.label}`);\n }\n lines.push('');\n}\n\nlines.push(`\ud83d\udccb ${data.upcoming_count} invoice(s) upcoming`);\nlines.push(`Total tracked: ${data.total_invoices}`);\n\nreturn [{\n json: {\n message: lines.join('\\n'),\n paid_count: data.paid_count,\n overdue_count: data.overdue_count,\n upcoming_count: data.upcoming_count\n }\n}];"
},
"typeVersion": 2
},
{
"id": "8284d459-6b14-428c-84c2-208511b97546",
"name": "SL Send Notification",
"type": "n8n-nodes-base.slack",
"position": [
1152,
-48
],
"parameters": {
"text": "={{ $json.message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "8110087c-5802-4805-bedb-151a9261bb02",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-112,
-272
],
"parameters": {
"color": 6,
"width": 272,
"height": 560,
"content": "## 1. Trigger\n\nRuns every 15 minutes.\nPolls Pennylane for all customer invoices.\n\nAdjust the schedule interval in the\nSchedule Trigger node to fit your needs."
},
"typeVersion": 1
},
{
"id": "07df7bfc-ded9-4119-b697-706ed1710194",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
-272
],
"parameters": {
"color": 3,
"width": 272,
"height": 560,
"content": "## 2. Fetch invoices\n\nRetrieves all customer invoices from Pennylane.\n\nEndpoint: GET /customer_invoices\n\nNote: the Pennylane API does not support\nfiltering by status or paid fields.\nAll filtering is done in the next Code node."
},
"typeVersion": 1
},
{
"id": "f4e10525-59ed-46a2-ad6b-1b2b8e4bb789",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
432,
-272
],
"parameters": {
"color": 3,
"width": 416,
"height": 560,
"content": "## 3. Classify & filter\n\nClassifies each invoice into 3 categories:\n- paid: invoice has been settled\n- overdue: past deadline and still unpaid\n- upcoming: not yet due\n\nOnly triggers a notification if there are\npaid or overdue invoices (has_updates = true).\n\nIf all invoices are upcoming, the workflow\nends silently via Set Done."
},
"typeVersion": 1
},
{
"id": "ee1f614f-fc39-4d68-b1e6-74dc303b0297",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
-272
],
"parameters": {
"color": 4,
"width": 512,
"height": 560,
"content": "## 4. Notify\n\nBuilds a summary message with:\n- List of newly paid invoices\n- List of overdue invoices\n- Count of upcoming invoices\n\nSends to Slack. Replace with your preferred\nnotification channel (Telegram, Email, etc.)."
},
"typeVersion": 1
},
{
"id": "4f5a9ddb-f537-4282-8c6a-47a3b36f30b5",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1360,
-272
],
"parameters": {
"color": 4,
"width": 368,
"height": 560,
"content": "## 5. Done\n\nNo paid or overdue invoices detected.\nWorkflow ends silently.\n\nThis node ensures a clean execution log\nin n8n. No notification is sent."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"callerPolicy": "workflowsFromSameOwner",
"timeSavedMode": "fixed",
"availableInMCP": true,
"executionOrder": "v1"
},
"connections": {
"IF Has Updates": {
"main": [
[
{
"node": "Code Build Payment Notification",
"type": "main",
"index": 0
}
],
[
{
"node": "Set Done",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "PL Fetch Invoices",
"type": "main",
"index": 0
}
]
]
},
"PL Fetch Invoices": {
"main": [
[
{
"node": "Code Filter Status Changes",
"type": "main",
"index": 0
}
]
]
},
"Code Filter Status Changes": {
"main": [
[
{
"node": "IF Has Updates",
"type": "main",
"index": 0
}
]
]
},
"Code Build Payment Notification": {
"main": [
[
{
"node": "SL Send Notification",
"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.
httpHeaderAuthslackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Teams using Pennylane (French accounting platform) who want automatic alerts when invoices are paid or become overdue, without checking Pennylane manually.
Source: https://n8n.io/workflows/15188/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow is an automated employee time tracking and reporting system that monitors weekly work hours via TMetric, then delivers personalized summaries directly to each team member on Slack. It co
Import Productboard Notes Companies And Features Into Snowflake. Uses stickyNote, httpRequest, splitOut, snowflake. Scheduled trigger; 35 nodes.
Import Productboard Notes, Companies and Features into Snowflake. Uses stickyNote, httpRequest, splitOut, snowflake. Scheduled trigger; 35 nodes.
This workflow imports Productboard data into Snowflake, automating data extraction, mapping, and updates for features, companies, and notes. It supports scheduled weekly updates, data cleansing, and S
This workflow streamlines the entire inventory replenishment process by leveraging AI for demand forecasting and intelligent logic for supplier selection. It aggregates data from multiple sources—POS