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.
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.
This n8n workflow automates the transformation of raw text ideas into structured visual diagrams and content assets using NapkinAI.
Receive request via webhook with customer question Analyze sentiment and detect urgency using JavaScript Send urgent alerts to Slack for critical cases Search knowledge base and fetch conversation his
Bidirectional Knowledge Sync Between AppFlowy and Affine. Uses postgres, n8n-nodes-appflowy, httpRequest. Webhook trigger; 22 nodes.