This workflow follows the Emailsend → HTTP Request 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": "VenueDesk \u2014 Billing Cycle Daily Trigger",
"active": true,
"nodes": [
{
"id": "bct-001",
"name": "Schedule: Daily at 08:00",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
-720,
160
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
}
},
{
"id": "bct-003",
"name": "IF: Any Due Today?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-240,
160
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-has-rows",
"leftValue": "={{ $json.schedule_id }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
}
}
},
{
"id": "bct-006",
"name": "Code: Format Email",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
0
],
"parameters": {
"jsCode": "const items = $input.all();\nif (!items.length || !items[0].json.schedule_id) return [];\n\nconst src = $('DB: Find Due Billing Cycles').item.json;\nconst opItem = $('DB: Create Outstanding Payment').item.json;\nconst dueFormatted = opItem.due_date\n ? new Date(opItem.due_date + 'T00:00:00Z').toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })\n : '\u2014';\nconst freq = (src.frequency || 'recurring').charAt(0).toUpperCase() + (src.frequency || 'recurring').slice(1);\nconst cycleNum = src.total_cycles && src.remaining_cycles ? (src.total_cycles - src.remaining_cycles + 1) : null;\nconst cycleStr = cycleNum && src.total_cycles ? ` (Cycle ${cycleNum} of ${src.total_cycles})` : '';\nconst seriesStr = src.series_reference ? ` \u00b7 ${src.series_reference}` : '';\nconst subject = `Recurring booking payment due${seriesStr} \u2014 \u00a3${parseFloat(src.amount_due).toFixed(2)}`;\nconst body = `<p>Dear ${src.customer_name || 'Valued Customer'},</p>\n<p>This is a friendly reminder that your ${freq} booking payment is due${cycleStr}:</p>\n<table style=\"border-collapse:collapse;font-family:sans-serif;font-size:14px\">\n ${src.series_reference ? `<tr><td style=\"padding:4px 12px 4px 0;color:#64748b\">Series ref:</td><td style=\"padding:4px 0\"><strong>${src.series_reference}</strong></td></tr>` : ''}\n <tr><td style=\"padding:4px 12px 4px 0;color:#64748b\">Room:</td><td style=\"padding:4px 0\"><strong>${src.room_name || '\u2014'}</strong></td></tr>\n <tr><td style=\"padding:4px 12px 4px 0;color:#64748b\">Amount due:</td><td style=\"padding:4px 0\"><strong>\u00a3${parseFloat(src.amount_due).toFixed(2)}</strong></td></tr>\n <tr><td style=\"padding:4px 12px 4px 0;color:#64748b\">Due by:</td><td style=\"padding:4px 0\">${dueFormatted}</td></tr>\n <tr><td style=\"padding:4px 12px 4px 0;color:#64748b\">Remaining payments:</td><td style=\"padding:4px 0\">${src.remaining_cycles || '\u2014'}</td></tr>\n</table>\n<p>Please contact us to arrange payment before the due date to keep your recurring booking active.</p>\n<p>Thank you,<br>The VenueDesk Team</p>`;\n\nreturn [{ json: {\n customer_email: src.customer_email,\n customer_name: src.customer_name,\n customer_id: src.customer_id,\n tenant_id: src.tenant_id,\n recurring_rule_id: src.recurring_rule_id,\n amount_due: src.amount_due,\n due_date: opItem.due_date || '',\n period_start: opItem.period_start || '',\n email_subject: subject,\n email_html: body\n} }];"
}
},
{
"id": "bct-007",
"name": "Email: Payment Reminder",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
720,
0
],
"continueOnFail": true,
"parameters": {
"fromEmail": "bookings@venuedesk.co.uk",
"toEmail": "={{ $json.customer_email }}",
"subject": "={{ $json.email_subject }}",
"emailFormat": "html",
"html": "={{ $json.email_html }}",
"options": {}
}
},
{
"id": "bct-010",
"name": "No Billing Due Today",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
0,
320
],
"alwaysOutputData": true,
"parameters": {}
},
{
"parameters": {
"method": "GET",
"url": "https://api.venuedesk.co.uk/recurring/due-billing-cycles",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.N8N_SERVICE_JWT }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"options": {
"response": {
"response": {
"fullResponse": false,
"neverError": true
}
},
"timeout": 15000
}
},
"id": "bct-http-due",
"name": "HTTP: Get Due Billing Cycles",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"continueOnFail": true,
"position": [
-200,
300
]
},
{
"parameters": {
"jsCode": "const resp = $input.first().json;\nconst rows = resp.data || (Array.isArray(resp) ? resp : [resp]);\nif (!rows.length) return [];\nreturn rows.map(row => ({ json: row }));",
"mode": "runOnceForAllItems"
},
"id": "bct-flat-due",
"name": "DB: Find Due Billing Cycles",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
0,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.venuedesk.co.uk/recurring/create-billing-record",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.N8N_SERVICE_JWT }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ schedule_id: $json.schedule_id, recurring_rule_id: $json.recurring_rule_id, customer_id: $json.customer_id, period_end: $json.period_end, amount_due: $json.amount_due, billing_day: $json.billing_day, total_cycles: $json.total_cycles || null, cycle_number: $json.total_cycles && $json.remaining_cycles ? ($json.total_cycles - $json.remaining_cycles + 1) : null }) }}",
"options": {
"response": {
"response": {
"fullResponse": false,
"neverError": true
}
},
"timeout": 15000
}
},
"id": "bct-http-brec",
"name": "HTTP: Create Billing Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"continueOnFail": true,
"position": [
600,
300
]
},
{
"parameters": {
"jsCode": "return [{ json: ($input.first().json.data || $input.first().json) }];",
"mode": "runOnceForAllItems"
},
"id": "bct-flat-op",
"name": "DB: Create Outstanding Payment",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
800,
300
]
},
{
"parameters": {
"jsCode": "return [{ json: ($input.first().json.data || $input.first().json) }];",
"mode": "runOnceForAllItems"
},
"id": "bct-flat-dec",
"name": "DB: Decrement Remaining Cycles",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
1000,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.venuedesk.co.uk/recurring/mark-billing-email-sent",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.N8N_SERVICE_JWT }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ recurring_rule_id: $('DB: Find Due Billing Cycles').item.json.recurring_rule_id, period_start: $('DB: Create Outstanding Payment').item.json.period_start || $('DB: Find Due Billing Cycles').item.json.period_end, customer_id: $('DB: Find Due Billing Cycles').item.json.customer_id, customer_email: $('DB: Find Due Billing Cycles').item.json.customer_email || '', amount_due: $('DB: Find Due Billing Cycles').item.json.amount_due, due_date: $('DB: Create Outstanding Payment').item.json.due_date || '', email_subject: 'Payment reminder: ' + ($('DB: Find Due Billing Cycles').item.json.series_reference || 'recurring booking') }) }}",
"options": {
"response": {
"response": {
"fullResponse": false,
"neverError": true
}
},
"timeout": 15000
}
},
"id": "bct-http-email",
"name": "HTTP: Mark Email Sent",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"continueOnFail": true,
"position": [
1600,
300
]
},
{
"parameters": {
"jsCode": "return [{ json: ($input.first().json.data || $input.first().json) }];",
"mode": "runOnceForAllItems"
},
"id": "bct-flat-ms",
"name": "DB: Mark Email Sent",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
1800,
300
]
},
{
"parameters": {
"jsCode": "return [{ json: ($input.first().json.data || $input.first().json) }];",
"mode": "runOnceForAllItems"
},
"id": "bct-flat-log",
"name": "DB: Log Reminder Sent",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
2000,
300
]
},
{
"parameters": {
"jsCode": "return [{ json: ($input.first().json) }];",
"mode": "runOnceForAllItems"
},
"id": "bct-pass-nbt",
"name": "DB: Log No Billing Today",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"continueOnFail": true,
"position": [
200,
700
]
}
],
"connections": {
"Schedule: Daily at 08:00": {
"main": [
[
{
"node": "HTTP: Get Due Billing Cycles",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Get Due Billing Cycles": {
"main": [
[
{
"node": "DB: Find Due Billing Cycles",
"type": "main",
"index": 0
}
]
]
},
"DB: Find Due Billing Cycles": {
"main": [
[
{
"node": "IF: Any Due Today?",
"type": "main",
"index": 0
}
]
]
},
"IF: Any Due Today?": {
"main": [
[
{
"node": "HTTP: Create Billing Record",
"type": "main",
"index": 0
}
],
[
{
"node": "No Billing Due Today",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Create Billing Record": {
"main": [
[
{
"node": "DB: Create Outstanding Payment",
"type": "main",
"index": 0
}
]
]
},
"DB: Create Outstanding Payment": {
"main": [
[
{
"node": "DB: Decrement Remaining Cycles",
"type": "main",
"index": 0
}
]
]
},
"DB: Decrement Remaining Cycles": {
"main": [
[
{
"node": "Code: Format Email",
"type": "main",
"index": 0
}
]
]
},
"Code: Format Email": {
"main": [
[
{
"node": "Email: Payment Reminder",
"type": "main",
"index": 0
}
]
]
},
"Email: Payment Reminder": {
"main": [
[
{
"node": "HTTP: Mark Email Sent",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Mark Email Sent": {
"main": [
[
{
"node": "DB: Mark Email Sent",
"type": "main",
"index": 0
}
]
]
},
"DB: Mark Email Sent": {
"main": [
[
{
"node": "DB: Log Reminder Sent",
"type": "main",
"index": 0
}
]
]
},
"No Billing Due Today": {
"main": [
[
{
"node": "DB: Log No Billing Today",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
VenueDesk — Billing Cycle Daily Trigger. Uses emailSend, httpRequest. Scheduled trigger; 14 nodes.
Source: https://github.com/AndyJay72/VenueDesk/blob/main/n8n-workflows/BillingCycleTrigger.json — 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.
Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.
This workflow is an improvement of this workflow by Greg Brzezinka.
N8N-Self-Updater. Uses ssh, emailSend, httpRequest. Scheduled trigger; 27 nodes.
> An automated n8n workflow originally built for DigitalOcean-based n8n deployments, but fully compatible with any VPS or cloud hosting (e.g., AWS, Google Cloud, Hetzner, Linode, etc.) where n8n ru
What if you could spot a major sales problem—or a winning campaign—the very next morning, instead of weeks later? Imagine receiving a beautiful, data-rich alert directly in your inbox the moment your