This workflow follows the HTTP Request → Postgres 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": "Mercanta \u2014 WA Bot",
"active": false,
"settings": {
"executionOrder": "v1"
},
"nodes": [
{
"id": "b0000001-0000-0000-0000-000000000001",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
240,
600
],
"parameters": {
"httpMethod": "POST",
"path": "wa-bot",
"responseMode": "onReceived",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000003",
"name": "Parse & Intent",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
600
],
"parameters": {
"jsCode": "// \u2500\u2500 Extract message from Evolution API payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst body = $input.item.json.body || $input.item.json;\nconst data = body?.data || body;\nconst jid = data?.key?.remoteJid || '';\nconst sender = jid.replace('@s.whatsapp.net','').replace('@g.us','');\nconst isFromMe = data?.key?.fromMe === true;\nconst isGroup = jid.includes('@g.us');\nconst msgObj = data?.message || {};\nconst firstKey = Object.keys(msgObj)[0] || '';\n\nlet text = '';\nif (firstKey === 'conversation') text = msgObj.conversation || '';\nelse if (firstKey === 'extendedTextMessage') text = msgObj.extendedTextMessage?.text || '';\ntext = text.trim();\n\n// \u2500\u2500 Config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst BUSINESS_ACCOUNT_ID = 'd72e900f-a09e-4b8c-bf77-aff843ef754a';\n\n// \u2500\u2500 Ignore non-text, own messages, groups \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nif (!text || isFromMe || isGroup) {\n return [{ json: { intent: 'ignore', sender, text, itemName: '', qty: 1, BUSINESS_ACCOUNT_ID } }];\n}\n\n// \u2500\u2500 Classify intent \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Best routing: single classification here keeps Switch node simple and testable.\nconst lower = text.toLowerCase();\nlet intent = 'buy'; // default: treat unrecognized text as item name\nlet itemName = text;\nlet qty = 1;\n\nif (/^(hi|hello|hey|start|menu|food|list|what|show|namaste|hola|help)\\b/i.test(lower)) {\n intent = 'menu'; itemName = '';\n\n} else if (/^(status|token|my order|track|where|when will|order status)\\b/i.test(lower)) {\n intent = 'status'; itemName = '';\n\n} else if (/^(receipt|bill|invoice)\\b/i.test(lower)) {\n intent = 'receipt'; itemName = '';\n\n} else if (/^(buy|order|get|give me|i want)\\s/i.test(lower)) {\n // Parse 'buy Butter Chicken 2' \u2192 itemName='Butter Chicken', qty=2\n const m = text.match(/^(?:buy|order|get|give me|i want)\\s+(.+)/i);\n if (m) {\n const parts = m[1].trim().split(/\\s+/);\n const last = parseInt(parts[parts.length - 1]);\n if (!isNaN(last) && last > 0 && parts.length > 1) {\n qty = last;\n itemName = parts.slice(0, -1).join(' ');\n } else {\n itemName = m[1].trim();\n }\n }\n // else: itemName stays as full text (default)\n}\n\nreturn [{ json: { intent, sender, text, itemName, qty, BUSINESS_ACCOUNT_ID } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000004",
"name": "Intent Router",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
720,
600
],
"parameters": {
"dataType": "string",
"value1": "={{ $json.intent }}",
"rules": {
"rules": [
{
"value2": "ignore"
},
{
"value2": "menu"
},
{
"value2": "buy"
},
{
"value2": "status"
},
{
"value2": "receipt"
}
]
},
"fallbackOutput": 5
}
},
{
"id": "b0000001-0000-0000-0000-000000000005",
"name": "Fetch Menu",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
960,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, category, item_name, price, is_vegetarian, is_spicy FROM restaurant_menu WHERE business_account_id = '{{ $('Parse & Intent').item.json.BUSINESS_ACCOUNT_ID }}' AND is_available = true ORDER BY category, sort_order, item_name;",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000006",
"name": "Format Menu",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
400
],
"parameters": {
"jsCode": "const rows = $input.all();\nif (!rows.length) return [{ json: { reply: 'Sorry, no items available right now. Check back soon!' } }];\n\nlet out = '*Mercanta Menu*\\n\\n';\nlet cat = '';\nfor (const r of rows) {\n const i = r.json;\n if (i.category !== cat) { cat = i.category; out += `*${cat}*\\n`; }\n const tags = [];\n if (i.is_vegetarian) tags.push('\ud83c\udf3f');\n if (i.is_spicy) tags.push('\ud83c\udf36');\n out += ` \u2022 ${i.item_name}${tags.length ? ' '+tags.join('') : ''} \u2014 \u20b9${parseFloat(i.price).toFixed(0)}\\n`;\n}\nout += '\\n_Just type an item name to order, e.g._ *Paneer Tikka*\\n_Type *status* to track your order_';\nreturn [{ json: { reply: out } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000007",
"name": "Send WA: Menu",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1440,
400
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000008",
"name": "Lookup Item",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
960,
600
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, item_name, category, price FROM restaurant_menu WHERE business_account_id = '{{ $json.BUSINESS_ACCOUNT_ID }}' AND is_available = true AND LOWER(item_name) LIKE LOWER('%{{ $json.itemName.replace(/'/g, \"''\") }}%') ORDER BY CASE WHEN LOWER(item_name) = LOWER('{{ $json.itemName.replace(/'/g, \"''\") }}') THEN 0 ELSE 1 END, item_name LIMIT 1;",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000009",
"name": "Build Order",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
600
],
"parameters": {
"jsCode": "const rows = $input.all();\nconst ctx = $('Parse & Intent').item.json;\n\nif (!rows.length || !rows[0].json.id) {\n return [{ json: {\n found: false,\n reply: `Sorry, *${ctx.itemName}* isn't available. Type *menu* to see what we have.`,\n sender: ctx.sender\n } }];\n}\n\nconst item = rows[0].json;\nconst qty = ctx.qty || 1;\nconst total = parseFloat(item.price) * qty;\n\nreturn [{ json: {\n found: true,\n itemId: item.id,\n itemName: item.item_name,\n price: parseFloat(item.price),\n qty,\n total,\n totalPaise: Math.round(total * 100),\n sender: ctx.sender,\n BUSINESS_ACCOUNT_ID: ctx.BUSINESS_ACCOUNT_ID\n} }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000010",
"name": "Item Found?",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
1440,
600
],
"parameters": {
"dataType": "boolean",
"value1": "={{ $json.found }}",
"rules": {
"rules": [
{
"value2": true
}
]
},
"fallbackOutput": 1
}
},
{
"id": "b0000001-0000-0000-0000-000000000011",
"name": "Create Payment Link",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1680,
500
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"parameters": {
"method": "POST",
"url": "https://api.razorpay.com/v1/payment_links",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "json",
"body": "={{ JSON.stringify({ amount: $json.totalPaise, currency: 'INR', accept_partial: false, description: `Order: ${$json.qty}x ${$json.itemName}`, customer: { contact: `+${$json.sender}` }, notify: { whatsapp: false, sms: false }, reminder_enable: false, notes: { item_name: $json.itemName, qty: $json.qty, sender: $json.sender, business_account_id: $json.BUSINESS_ACCOUNT_ID, item_id: $json.itemId, price: $json.price } }) }}",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000012",
"name": "Save Pending Sale",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1920,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO sales (customer_name, total, subtotal, payment_method, payment_details, business_account_id, is_restaurant_order) VALUES ('WhatsApp Customer', {{ $('Build Order').item.json.total }}, {{ $('Build Order').item.json.total }}, 'upi', jsonb_build_object('razorpay_payment_link_id', '{{ $('Create Payment Link').item.json.id }}', 'status', 'pending', 'sender', '{{ $('Build Order').item.json.sender }}'), '{{ $('Build Order').item.json.BUSINESS_ACCOUNT_ID }}', true) RETURNING id;",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000013",
"name": "Save Sale Item",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
2160,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO sale_items (sale_id, sku, item_name, quantity, price) VALUES ('{{ $('Save Pending Sale').item.json.id }}', '{{ $('Build Order').item.json.itemId }}', '{{ $('Build Order').item.json.itemName.replace(/'/g, \"''\") }}', {{ $('Build Order').item.json.qty }}, {{ $('Build Order').item.json.price }});",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000014",
"name": "Format Pay Reply",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2400,
500
],
"parameters": {
"jsCode": "const order = $('Build Order').item.json;\nconst link = $('Create Payment Link').item.json;\nconst reply = `*Order Summary*\\n\\n\ud83d\udce6 ${order.qty}\u00d7 ${order.itemName}\\n\ud83d\udcb0 Total: \u20b9${order.total.toFixed(0)}\\n\\n\ud83d\udcb3 *Pay to confirm your order:*\\n${link.short_url}\\n\\n_Your token number will be sent once payment is received._\\n_Type *status* to track anytime._`;\nreturn [{ json: { reply } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000015",
"name": "Send WA: Pay",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2640,
500
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000016",
"name": "Format Not Found",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1680,
700
],
"parameters": {
"jsCode": "return [{ json: { reply: $json.reply } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000017",
"name": "Send WA: Not Found",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1920,
700
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000018",
"name": "Lookup Status",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
960,
800
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "SELECT ot.token_number, ot.status, ot.created_at, ot.ready_at, tqs.estimated_minutes, si.item_name, si.quantity FROM order_tokens ot JOIN sales s ON s.id = ot.sale_id JOIN sale_items si ON si.sale_id = s.id LEFT JOIN token_queue_status tqs ON tqs.token_id = ot.id LEFT JOIN customers c ON c.id = s.customer_id WHERE (c.phone = '{{ $json.sender }}' OR s.payment_details->>'sender' = '{{ $json.sender }}') AND ot.is_active = true AND ot.business_account_id = '{{ $json.BUSINESS_ACCOUNT_ID }}' ORDER BY ot.created_at DESC LIMIT 1;",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000019",
"name": "Format Status",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
800
],
"parameters": {
"jsCode": "const rows = $input.all();\nif (!rows.length || !rows[0].json.token_number) {\n return [{ json: { reply: 'No active orders found. Type *menu* to browse our items.' } }];\n}\nconst t = rows[0].json;\nconst statusEmoji = { ordered:'\ud83d\udd50', confirmed:'\u2705', preparing:'\ud83d\udc68\u200d\ud83c\udf73', prepared:'\ud83c\udf7d', ready:'\ud83d\udd14', served:'\u2705', cancelled:'\u274c' };\nconst emoji = statusEmoji[t.status] || '\ud83d\udd50';\nlet reply = `${emoji} *Token #${t.token_number}*\\n\\nStatus: *${t.status.toUpperCase()}*\\n\ud83d\udce6 ${t.item_name} \u00d7${t.quantity}`;\nif (t.estimated_minutes) reply += `\\n\u23f1 Est. wait: ~${t.estimated_minutes} min`;\nif (t.status === 'ready') reply += '\\n\\n*Your order is ready for pickup!*\\nPlease collect at the counter.';\nreturn [{ json: { reply } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000020",
"name": "Send WA: Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1440,
800
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000021",
"name": "Lookup Receipt",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
960,
1000
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"parameters": {
"operation": "executeQuery",
"query": "SELECT s.date, s.total, s.token_number, si.item_name, si.quantity, si.price, ot.status as order_status FROM sales s JOIN sale_items si ON si.sale_id = s.id LEFT JOIN order_tokens ot ON ot.sale_id = s.id LEFT JOIN customers c ON c.id = s.customer_id WHERE (c.phone = '{{ $json.sender }}' OR s.payment_details->>'sender' = '{{ $json.sender }}') AND s.business_account_id = '{{ $json.BUSINESS_ACCOUNT_ID }}' AND s.is_restaurant_order = true ORDER BY s.date DESC LIMIT 5;",
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000022",
"name": "Format Receipt",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
1000
],
"parameters": {
"jsCode": "const rows = $input.all();\nif (!rows.length || !rows[0].json.date) {\n return [{ json: { reply: 'No orders found yet. Type *menu* to browse.' } }];\n}\nconst latest = rows[0].json;\nconst date = new Date(latest.date).toLocaleString('en-IN', { timeZone: 'Asia/Kolkata', day:'2-digit', month:'short', hour:'2-digit', minute:'2-digit', hour12:true });\nlet reply = `\ud83e\uddfe *Last Order*\\n\ud83d\udcc5 ${date}\\n\\n`;\nfor (const r of rows) {\n reply += ` \u2022 ${r.json.item_name} \u00d7${r.json.quantity} @ \u20b9${parseFloat(r.json.price).toFixed(0)}\\n`;\n}\nreply += `\\n\ud83d\udcb0 *Total: \u20b9${parseFloat(latest.total).toFixed(0)}*`;\nif (latest.token_number) reply += `\\n\ud83c\udfab Token: *#${latest.token_number}*`;\nif (latest.order_status) reply += `\\n\ud83d\udccb Status: ${latest.order_status}`;\nreturn [{ json: { reply } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000023",
"name": "Send WA: Receipt",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1440,
1000
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
},
{
"id": "b0000001-0000-0000-0000-000000000024",
"name": "Format Help",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
960,
1200
],
"parameters": {
"jsCode": "return [{ json: { reply: '*Welcome to Mercanta!*\\n\\nHere is what you can do:\\n *menu* \u2014 browse our menu\\n *<item name>* \u2014 type any item to order\\n *buy <item> <qty>* \u2014 order with quantity\\n *status* \u2014 track your current order\\n *receipt* \u2014 view your last order\\n\\n_Example: type_ *Paneer Tikka* _or_ *buy Butter Chicken 2*' } }];"
}
},
{
"id": "b0000001-0000-0000-0000-000000000025",
"name": "Send WA: Help",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1200,
1200
],
"parameters": {
"method": "POST",
"url": "http://evolution-api:8080/message/sendText/musaib_bot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "Musaib_2026_Secure"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "number",
"value": "={{ $('Parse & Intent').item.json.sender }}"
},
{
"name": "text",
"value": "={{ $json.reply }}"
}
]
},
"options": {}
}
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Parse & Intent",
"type": "main",
"index": 0
}
]
]
},
"Parse & Intent": {
"main": [
[
{
"node": "Intent Router",
"type": "main",
"index": 0
}
]
]
},
"Intent Router": {
"main": [
[],
[
{
"node": "Fetch Menu",
"type": "main",
"index": 0
}
],
[
{
"node": "Lookup Item",
"type": "main",
"index": 0
}
],
[
{
"node": "Lookup Status",
"type": "main",
"index": 0
}
],
[
{
"node": "Lookup Receipt",
"type": "main",
"index": 0
}
],
[
{
"node": "Format Help",
"type": "main",
"index": 0
}
]
]
},
"Fetch Menu": {
"main": [
[
{
"node": "Format Menu",
"type": "main",
"index": 0
}
]
]
},
"Format Menu": {
"main": [
[
{
"node": "Send WA: Menu",
"type": "main",
"index": 0
}
]
]
},
"Lookup Item": {
"main": [
[
{
"node": "Build Order",
"type": "main",
"index": 0
}
]
]
},
"Build Order": {
"main": [
[
{
"node": "Item Found?",
"type": "main",
"index": 0
}
]
]
},
"Item Found?": {
"main": [
[
{
"node": "Create Payment Link",
"type": "main",
"index": 0
}
],
[
{
"node": "Format Not Found",
"type": "main",
"index": 0
}
]
]
},
"Create Payment Link": {
"main": [
[
{
"node": "Save Pending Sale",
"type": "main",
"index": 0
}
]
]
},
"Save Pending Sale": {
"main": [
[
{
"node": "Save Sale Item",
"type": "main",
"index": 0
}
]
]
},
"Save Sale Item": {
"main": [
[
{
"node": "Format Pay Reply",
"type": "main",
"index": 0
}
]
]
},
"Format Pay Reply": {
"main": [
[
{
"node": "Send WA: Pay",
"type": "main",
"index": 0
}
]
]
},
"Format Not Found": {
"main": [
[
{
"node": "Send WA: Not Found",
"type": "main",
"index": 0
}
]
]
},
"Lookup Status": {
"main": [
[
{
"node": "Format Status",
"type": "main",
"index": 0
}
]
]
},
"Format Status": {
"main": [
[
{
"node": "Send WA: Status",
"type": "main",
"index": 0
}
]
]
},
"Lookup Receipt": {
"main": [
[
{
"node": "Format Receipt",
"type": "main",
"index": 0
}
]
]
},
"Format Receipt": {
"main": [
[
{
"node": "Send WA: Receipt",
"type": "main",
"index": 0
}
]
]
},
"Format Help": {
"main": [
[
{
"node": "Send WA: Help",
"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.
httpBasicAuthpostgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Mercanta — WA Bot. Uses postgres, httpRequest. Webhook trigger; 24 nodes.
Source: https://github.com/MusaibBashir/Mercanta/blob/3b87bdb0b121f1e40559b04799d1c71c05e9cd59/n8n/wa_bot.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.
CMM. Uses httpRequest, postgres, redis. Webhook trigger; 90 nodes.
Scraping. Uses httpRequest, postgres, @apify/n8n-nodes-apify, respondToWebhook. Webhook trigger; 61 nodes.
Workflow B — AI Listing Engine. Uses httpRequest, postgres, errorTrigger. Webhook trigger; 47 nodes.
LogSentinel Workflow. Uses postgres, emailSend, httpRequest. Webhook trigger; 44 nodes.
Post-Prayer. Uses postgres, httpRequest. Webhook trigger; 44 nodes.