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": "Workflow B: Optimized User-Loan Matching",
"nodes": [
{
"parameters": {
"path": "user-loan-match",
"options": {
"responseData": true
}
},
"name": "Trigger: New CSV Upload",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
-96,
-16
],
"id": "9207b73e-1a5f-4040-a164-644c7eb6ef5c"
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT\n user_id,\n monthly_income,\n credit_score,\n employment_status,\n age\nFROM\n users\nWHERE\n users.created_at >= NOW() - INTERVAL '1 day';",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
304,
-144
],
"id": "bf7e13f7-ad2c-4bd8-bd32-d76b46cd28d0",
"name": "Execute a SQL query",
"alwaysOutputData": true,
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT\n id AS product_id,\n product_name,\n min_income,\n min_credit_score,\n max_amount\nFROM\n loan_products;",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
304,
112
],
"id": "ae8139e2-9469-4825-9df3-510d0347856a",
"name": "Execute a SQL query1",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineAll",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
592,
-16
],
"id": "c34eb3cf-98e8-42da-a0ce-0c3021da3035",
"name": "Merge",
"alwaysOutputData": true
},
{
"parameters": {
"jsCode": "const matches = [];\n\n// The 'items' variable holds the array of data from the previous node (the Merge node)\nfor (const item of items) {\n // Access data directly from the flat merged item structure\n const user = {\n user_id: item.json.user_id,\n monthly_income: parseFloat(item.json.monthly_income),\n credit_score: parseInt(item.json.credit_score)\n };\n\n const product = {\n product_id: item.json.product_id,\n // Use product-specific min_credit_score if available, otherwise default to a high standard (e.g., 700)\n // If min_credit_score is null in the merged data, we'll use a hardcoded 700\n product_min_credit_score: parseInt(item.json.min_credit_score) || 700, \n max_amount: parseFloat(item.json.max_amount)\n };\n\n // --- Filtering Logic ---\n\n // 1. Hardcoded Credit Score Filter: MUST be >= 700\n if (user.credit_score < 700) {\n continue; // User does not meet the minimum general credit score\n }\n\n // 2. Product-Specific Credit Score Filter (if min_credit_score was available)\n if (user.credit_score < product.product_min_credit_score) {\n continue; // User does not meet the product-specific credit score\n }\n\n\n // 3. Repayment Capacity Calculation (The 5-Year Rule)\n const fixedExpense = 30000;\n const repaymentMonths = 60; // 5 years\n\n // Calculate Disposable Income after the fixed expense\n const disposableIncome = user.monthly_income - fixedExpense;\n\n // Calculate the required monthly payment if the user takes the MAX loan amount over 60 months\n const maxMonthlyRepayment = product.max_amount / repaymentMonths;\n \n // Eligibility Condition: Disposable income must be able to cover the required monthly payment\n const isEligibleForRepayment = disposableIncome >= maxMonthlyRepayment;\n\n // --- Match Creation ---\n\n if (isEligibleForRepayment) {\n // Calculate Match Score based on the repayment surplus (buffer)\n const bufferIncome = disposableIncome - maxMonthlyRepayment;\n \n // Base score (300 for meeting all criteria) + bonus points\n const matchScore = 300 + Math.floor(bufferIncome / 500); \n\n // Add the successful match to the output array\n matches.push({\n json: {\n user_id: user.user_id,\n product_id: product.product_id,\n match_score: matchScore,\n recommendation_strength: '5YR_REPAYMENT_CAPACITY_CHECK' \n }\n });\n }\n}\n\nreturn matches;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
800,
-16
],
"id": "ba42be2c-9461-42e0-bca0-e97fe20c3e7d",
"name": "Code in JavaScript"
},
{
"parameters": {
"schema": {
"__rl": true,
"value": "public",
"mode": "list",
"cachedResultName": "public"
},
"table": {
"__rl": true,
"value": "user_loan_matches",
"mode": "list",
"cachedResultName": "user_loan_matches"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"is_notified": false,
"match_score": "={{ $json.match_score }}",
"user_id": "={{ $json.user_id }}",
"product_id": "={{ $json.product_id }}",
"recommendation_strength": "={{ $json.recommendation_strength }}"
},
"matchingColumns": [
"id"
],
"schema": [
{
"id": "id",
"displayName": "id",
"required": false,
"defaultMatch": true,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "user_id",
"displayName": "user_id",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "product_id",
"displayName": "product_id",
"required": true,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "match_score",
"displayName": "match_score",
"required": true,
"defaultMatch": false,
"display": true,
"type": "number",
"canBeUsedToMatch": true
},
{
"id": "is_notified",
"displayName": "is_notified",
"required": false,
"defaultMatch": false,
"display": true,
"type": "boolean",
"canBeUsedToMatch": true
},
{
"id": "recommendation_strength",
"displayName": "recommendation_strength",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "notified_at",
"displayName": "notified_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true
},
{
"id": "created_at",
"displayName": "created_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true
},
{
"id": "updated_at",
"displayName": "updated_at",
"required": false,
"defaultMatch": false,
"display": true,
"type": "dateTime",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1008,
-16
],
"id": "b4da7219-707d-4328-bfbf-229b0cb7e1f8",
"name": "Insert rows in a table",
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "http://localhost:5678/webhook-test/970dbc79-d5ad-4a1e-b40c-ff1db74bd830",
"options": {
"allowUnauthorizedCerts": true
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1232,
-16
],
"id": "1ec8e6c0-0de8-466d-b07c-84b75c4c063d",
"name": "HTTP Request",
"executeOnce": true
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "Z49V1WgZwnbNUmqK",
"mode": "list",
"cachedResultUrl": "/workflow/Z49V1WgZwnbNUmqK",
"cachedResultName": "notification alert"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {},
"matchingColumns": [],
"schema": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {}
},
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.3,
"position": [
1088,
160
],
"id": "0decb02c-01c9-4241-9589-200a3b28ff24",
"name": "Call 'notification alert'"
}
],
"connections": {
"Trigger: New CSV Upload": {
"main": [
[
{
"node": "Execute a SQL query1",
"type": "main",
"index": 0
},
{
"node": "Execute a SQL query",
"type": "main",
"index": 0
}
]
]
},
"Execute a SQL query": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Execute a SQL query1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Insert rows in a table",
"type": "main",
"index": 0
}
]
]
},
"Insert rows in a table": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "207d91e7-04e7-41d6-a07b-6cfe3346e0f7",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "MAO5dMccw8sbyww3",
"tags": []
}
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
Workflow B: Optimized User-Loan Matching. Uses postgres, httpRequest. Webhook trigger; 8 nodes.
Source: https://github.com/Phemon420/loan_eligbility_check/blob/0b7b555a63ca78b3ed4bbc62514715743257d6b0/n8n/loan_matching.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.