This workflow follows the Error Trigger → 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": "Subflow \u2014 WA Send",
"nodes": [
{
"id": "was00001-0001-0001-0001-000000000001",
"name": "WA Send Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
200,
300
],
"parameters": {}
},
{
"id": "was00002-0002-0002-0002-000000000002",
"name": "Fetch Last Inbound Time",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"alwaysOutputData": true,
"position": [
440,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "SELECT COALESCE(EXTRACT(EPOCH FROM (NOW() - MAX(created_at))), 0) AS seconds_since_last_inbound FROM conversation_message WHERE conversation_id = $1::uuid AND direction = 'IN'",
"options": {
"queryReplacement": "={{ [($('WA Send Trigger').first()?.json?.conversationId || '00000000-0000-0000-0000-000000000000')] }}"
}
}
},
{
"id": "was00003-0003-0003-0003-000000000003",
"name": "Route Free-Form vs Template",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
680,
300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-window",
"leftValue": "={{ Number($json.seconds_since_last_inbound) }}",
"rightValue": 86400,
"operator": {
"type": "number",
"operation": "lt"
}
},
{
"id": "cond-no-template",
"leftValue": "={{ $('WA Send Trigger').first()?.json?.templateName ?? '' }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"options": {}
}
},
{
"id": "was00004-0004-0004-0004-000000000004",
"name": "Send Free-Form Message",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
920,
200
],
"parameters": {
"method": "POST",
"url": "={{ 'https://graph.facebook.com/v20.0/' + $env.WHATSAPP_PHONE_NUMBER_ID + '/messages' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.WHATSAPP_ACCESS_TOKEN }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"contentType": "json",
"jsonBody": "={{ { messaging_product: 'whatsapp', to: $('WA Send Trigger').first()?.json?.to, type: 'text', text: { body: $('WA Send Trigger').first()?.json?.body } } }}",
"options": {
"timeout": 20000,
"retry": {
"enabled": true,
"maxTries": 2,
"waitBetweenTries": 1000
},
"response": {
"response": {
"neverError": true
}
}
}
}
},
{
"id": "was00005-0005-0005-0005-000000000005",
"name": "Check Error 131047",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1160,
200
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "cond-131047-a",
"leftValue": "={{ ($json.error && $json.error.code) ?? 0 }}",
"rightValue": 131047,
"operator": {
"type": "number",
"operation": "equals"
}
},
{
"id": "cond-131047-b",
"leftValue": "={{ ($json.errors && $json.errors[0] && $json.errors[0].code) ?? 0 }}",
"rightValue": 131047,
"operator": {
"type": "number",
"operation": "equals"
}
}
]
},
"options": {}
}
},
{
"id": "was00006-0006-0006-0006-000000000006",
"name": "Send Template Message",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1400,
100
],
"parameters": {
"method": "POST",
"url": "={{ 'https://graph.facebook.com/v20.0/' + $env.WHATSAPP_PHONE_NUMBER_ID + '/messages' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.WHATSAPP_ACCESS_TOKEN }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"contentType": "json",
"jsonBody": "={{ (function() { const t = $('WA Send Trigger').first()?.json; const vars = (t?.templateVars || []); return { messaging_product: 'whatsapp', to: t?.to, type: 'template', template: { name: t?.templateName, language: { code: 'en' }, components: vars.length > 0 ? [{ type: 'body', parameters: vars.map(function(v) { return { type: 'text', text: String(v) }; }) }] : [] } }; })() }}",
"options": {
"timeout": 20000,
"retry": {
"enabled": true,
"maxTries": 2,
"waitBetweenTries": 1000
}
}
}
},
{
"id": "was00007-0007-0007-0007-000000000007",
"name": "Force Template \u2014 Window Expired",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
920,
400
],
"parameters": {
"method": "POST",
"url": "={{ 'https://graph.facebook.com/v20.0/' + $env.WHATSAPP_PHONE_NUMBER_ID + '/messages' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "={{ 'Bearer ' + $env.WHATSAPP_ACCESS_TOKEN }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"contentType": "json",
"jsonBody": "={{ (function() { const t = $('WA Send Trigger').first()?.json; const vars = (t?.templateVars || []); return { messaging_product: 'whatsapp', to: t?.to, type: 'template', template: { name: t?.templateName || 'still_interested_10d', language: { code: 'en' }, components: vars.length > 0 ? [{ type: 'body', parameters: vars.map(function(v) { return { type: 'text', text: String(v) }; }) }] : [] } }; })() }}",
"options": {
"timeout": 20000,
"retry": {
"enabled": true,
"maxTries": 2,
"waitBetweenTries": 1000
}
}
}
},
{
"id": "was00008-0008-0008-0008-000000000008",
"name": "Return Success",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1640,
200
],
"parameters": {
"mode": "manual",
"duplicateItem": false,
"assignments": {
"assignments": [
{
"id": "ws-success",
"name": "success",
"value": true,
"type": "boolean"
}
]
},
"options": {}
}
},
{
"id": "was00009-0009-0009-0009-000000000009",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
200,
600
],
"parameters": {}
},
{
"id": "was00010-0010-0010-0010-000000000010",
"name": "Log Unhandled Error",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"alwaysOutputData": true,
"position": [
440,
600
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO workflow_errors (workflow_name, execution_id, node_name, error_message, error_stack, input_payload) VALUES ('subflow-wa-send', $1, $2, $3, $4, $5::jsonb)",
"options": {
"queryReplacement": "={{ [$json.execution.id, $json.execution.lastNodeExecuted || 'unknown', $json.execution.error.message || 'unknown error', ($json.execution.error.stack ? $json.execution.error.stack.split('\\n')[0] : ''), '{\"source\":\"error_trigger\"}'] }}"
}
}
}
],
"connections": {
"WA Send Trigger": {
"main": [
[
{
"node": "Fetch Last Inbound Time",
"type": "main",
"index": 0
}
]
]
},
"Fetch Last Inbound Time": {
"main": [
[
{
"node": "Route Free-Form vs Template",
"type": "main",
"index": 0
}
]
]
},
"Route Free-Form vs Template": {
"main": [
[
{
"node": "Send Free-Form Message",
"type": "main",
"index": 0
}
],
[
{
"node": "Force Template \u2014 Window Expired",
"type": "main",
"index": 0
}
]
]
},
"Send Free-Form Message": {
"main": [
[
{
"node": "Check Error 131047",
"type": "main",
"index": 0
}
]
]
},
"Check Error 131047": {
"main": [
[
{
"node": "Send Template Message",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
},
"Send Template Message": {
"main": [
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
},
"Force Template \u2014 Window Expired": {
"main": [
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Log Unhandled Error",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "real-estate-automation"
},
{
"name": "subflow"
},
{
"name": "version-1.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.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Subflow — WA Send. Uses executeWorkflowTrigger, postgres, httpRequest, errorTrigger. Event-driven trigger; 10 nodes.
Source: https://github.com/jameszokah/real-estate-n8n-workflow/blob/ff6c75dac6b332a260a52efcb695ac4f3c962ed3/n8n-workflows/subflows/wa-send.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.
Subflow — PDF Generate. Uses executeWorkflowTrigger, httpRequest, postgres, errorTrigger. Event-driven trigger; 11 nodes.
Reagendamiento_v2. Uses executeWorkflowTrigger, redis, httpRequest, n8n-nodes-evolution-api. Event-driven trigger; 89 nodes.
Agendamiento_v2. Uses n8n-nodes-evolution-api, redis, httpRequest, executeWorkflowTrigger. Event-driven trigger; 59 nodes.
Cancelacion_v2. Uses executeWorkflowTrigger, redis, httpRequest, n8n-nodes-evolution-api. Event-driven trigger; 46 nodes.
Save_Extraction. Uses executeWorkflowTrigger, postgres, httpRequest. Event-driven trigger; 22 nodes.