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": "Payment Confirmation",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "flutterwave-webhook",
"responseMode": "lastNode",
"options": {}
},
"id": "fw-trigger",
"name": "Flutterwave Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
0,
0
]
},
{
"parameters": {
"functionCode": "// Verify Flutterwave webhook signature\nconst crypto = require('crypto');\nconst secretHash = $env.FLUTTERWAVE_WEBHOOK_VERIF_HASH;\nconst signature = $headers['verif-hash'];\n\nconst body = $input.first().json;\nconst computedHash = crypto.createHmac('sha256', secretHash).digest('hex');\n\nif (signature !== computedHash) {\n throw new Error('Invalid Flutterwave signature');\n}\n\nreturn [{ json: body }];"
},
"id": "fw-verify",
"name": "Verify Signature",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
200,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"id": "evt-charge",
"leftValue": "={{$json.event}}",
"rightValue": "charge.completed",
"operation": "equals"
}
]
}
},
"id": "fw-switch",
"name": "Switch: Event Type",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
400,
0
]
},
{
"parameters": {
"functionCode": "// Idempotency: check if already processed\nconst txRef = $input.first().json.tx_ref;\nconst redisKey = `webhook:processed:flutterwave:${txRef}`;\n\n// Store processed flag in Redis with 24h TTL\nreturn [{ json: { txRef, redisKey, alreadyProcessed: false } }];"
},
"id": "fw-idempotency",
"name": "Idempotency Check",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
600,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"id": "status-pending",
"leftValue": "={{$json.data.status}}",
"rightValue": "successful",
"operation": "equals"
}
]
}
},
"id": "fw-status-check",
"name": "Check Payment Status",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
800,
0
]
},
{
"parameters": {
"operation": "select",
"table": "orders",
"columns": "order_id, status",
"conditions": "tx_ref = '{{$json.tx_ref}}'"
},
"id": "fw-db-lookup",
"name": "Lookup Order in PostgreSQL",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
1000,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"id": "already-fulfilled",
"leftValue": "={{$json.status}}",
"rightValue": "fulfilled",
"operation": "equals"
}
]
}
},
"id": "fw-already-done",
"name": "Already Fulfilled?",
"type": "n8n-nodes-base.switch",
"typeVersion": 1,
"position": [
1200,
0
]
},
{
"parameters": {
"operation": "update",
"table": "orders",
"values": "status = 'paid'"
},
"id": "fw-update-paid",
"name": "Update Order to Paid",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
1400,
0
]
},
{
"parameters": {
"method": "POST",
"url": "={{$json.data.meta.productType === 'isp' ? 'https://api.proxy-seller.com/v1.0/order/create' : 'https://api.dataimpulse.com/reseller/order/create'}}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-API-KEY",
"value": "={{$env.PROXY_SELLER_API_KEY}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"body": "={{ $json.data }}",
"options": {
"timeout": 30000
}
},
"id": "fw-call-provider",
"name": "Call Provider API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1600,
0
]
},
{
"parameters": {
"functionCode": "// Test proxy IP \u2014 5s timeout\nconst proxy = $input.first().json;\nconst host = proxy.ip || proxy.data?.ip;\nconst port = proxy.port || proxy.data?.port;\n\n// Simple connectivity test via curl\nconst { execSync } = require('child_process');\ntry {\n execSync(`timeout 5 curl -x http://${host}:${port} https://ipinfo.io/ip`, { stdio: 'ignore' });\n return [{ json: { ...proxy, testPassed: true } }];\n} catch (e) {\n return [{ json: { ...proxy, testPassed: false } }];\n}"
},
"id": "fw-test-proxy",
"name": "Test Proxy IP",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1800,
0
]
},
{
"parameters": {
"operation": "update",
"table": "orders",
"values": "status = 'fulfilled', fulfilled_at = NOW()"
},
"id": "fw-save-fulfilled",
"name": "Save Fulfilled to PostgreSQL",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
2000,
0
]
},
{
"parameters": {
"message": "\ud83c\udf89 ORDER COMPLETE!\n\n\ud83c\uddf3\ud83c\uddec Your proxy is ready:\n\n\ud83d\udd17 IP: {{$json.ip}}\n\ud83d\udd0c Port: {{$json.port}}\n\ud83d\udc64 Username: {{$json.username}}\n\ud83d\udd10 Password: {{$json.password}}\n\n\ud83d\udccb Order ID: ORD-XXXXX\n\u23f0 Expires: [DATE]\n\nNeed help using it? Reply 'How to use' \ud83d\udcf1",
"extraOptions": {}
},
"id": "fw-send-creds",
"name": "Send Credentials via WhatsApp",
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1,
"position": [
2200,
0
]
},
{
"parameters": {
"operation": "update",
"table": "orders",
"values": "status = 'refunded'"
},
"id": "fw-auto-refund",
"name": "Auto Refund",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
2400,
200
]
},
{
"parameters": {
"message": "\u26a0\ufe0f We couldn't deliver your proxy. A full refund has been initiated.",
"extraOptions": {}
},
"id": "fw-refund-notify",
"name": "Notify Refund",
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1,
"position": [
2600,
200
]
}
],
"connections": {
"Flutterwave Webhook": {
"main": [
[
{
"node": "Verify Signature",
"type": "main",
"index": 0
}
]
]
},
"Verify Signature": {
"main": [
[
{
"node": "Switch: Event Type",
"type": "main",
"index": 0
}
]
]
},
"Switch: Event Type": {
"main": [
[
{
"node": "Idempotency Check",
"type": "main",
"index": 0
}
]
]
},
"Idempotency Check": {
"main": [
[
{
"node": "Check Payment Status",
"type": "main",
"index": 0
}
]
]
},
"Check Payment Status": {
"main": [
[
{
"node": "Lookup Order in PostgreSQL",
"type": "main",
"index": 0
}
]
]
},
"Lookup Order in PostgreSQL": {
"main": [
[
{
"node": "Already Fulfilled?",
"type": "main",
"index": 0
}
]
]
},
"Already Fulfilled?": {
"main": [
[
{
"node": "Update Order to Paid",
"type": "main",
"index": 0
}
],
[]
]
},
"Update Order to Paid": {
"main": [
[
{
"node": "Call Provider API",
"type": "main",
"index": 0
}
]
]
},
"Call Provider API": {
"main": [
[
{
"node": "Test Proxy IP",
"type": "main",
"index": 0
}
]
]
},
"Test Proxy IP": {
"main": [
[
{
"node": "Save Fulfilled to PostgreSQL",
"type": "main",
"index": 0
}
],
[
{
"node": "Auto Refund",
"type": "main",
"index": 0
}
]
]
},
"Save Fulfilled to PostgreSQL": {
"main": [
[
{
"node": "Send Credentials via WhatsApp",
"type": "main",
"index": 0
}
]
]
},
"Auto Refund": {
"main": [
[
{
"node": "Notify Refund",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"timezone": "Africa/Lagos"
},
"staticData": null,
"tags": [
"flutterwave",
"payment",
"provider"
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Payment Confirmation. Uses postgres, httpRequest, whatsApp. Webhook trigger; 14 nodes.
Source: https://github.com/sonnyagent30-beep/bunche/blob/8887b0da2107acb83f0c0632a8d7665b1adbfc44/.n8n/workflows/payment-confirmation.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.
Ban Claim Handler. Uses postgres, httpRequest, whatsApp, telegram. Webhook trigger; 20 nodes.
Ban Claim Handler. Uses postgres, httpRequest, whatsApp, telegram. Webhook trigger; 20 nodes.
Refund Handler. Uses postgres, minimax, httpRequest, whatsApp. Webhook trigger; 18 nodes.
Flujowhatsapp. Uses @aldinokemal2104/n8n-nodes-gowa, postgres, httpRequest. Webhook trigger; 65 nodes.
This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS