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": "22-ecommerce-etl-kpi-postgres",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "days",
"triggerAt": "00:00"
}
]
}
},
"id": "b2c3d4e5-1111-4444-8888-000000000001",
"name": "Schedule",
"type": "n8n-nodes-base.schedule",
"typeVersion": 1,
"position": [
240,
400
]
},
{
"parameters": {
"url": "https://jsonplaceholder.typicode.com/posts",
"method": "GET",
"options": {}
},
"id": "b2c3d4e5-2222-4444-8888-000000000002",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
460,
400
],
"notes": "\u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632\u06cc \u062f\u0631\u06cc\u0627\u0641\u062a \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0641\u0631\u0648\u0634 \u0627\u0632 API \u0641\u0631\u0648\u0634\u06af\u0627\u0647. \u062f\u0631 \u0645\u062d\u06cc\u0637 \u0648\u0627\u0642\u0639\u06cc\u060c URL \u0648 \u0647\u062f\u0631\u0647\u0627\u06cc \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u0631\u0627 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u06a9\u0646\u06cc\u062f."
},
{
"parameters": {
"jsCode": "// \u0645\u062d\u0627\u0633\u0628\u0647 KPI\u0647\u0627\u06cc \u0641\u0631\u0648\u0634 \u0627\u0632 \u0644\u06cc\u0633\u062a \u0622\u06cc\u062a\u0645\u200c\u0647\u0627\nconst items = $input.all();\n\n// \u0634\u0628\u06cc\u0647\u200c\u0633\u0627\u0632\u06cc \u0645\u0642\u062f\u0627\u0631 \u0641\u0631\u0648\u0634 \u0628\u0631\u0627\u06cc \u0647\u0631 \u0622\u06cc\u062a\u0645 (\u062f\u0631 \u0648\u0627\u0642\u0639\u06cc\u062a \u0627\u0632 \u0641\u06cc\u0644\u062f amount \u06cc\u0627 price \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0648\u0627\u0642\u0639\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f)\nlet totalRevenue = 0;\nitems.forEach(item => {\n // \u0641\u0631\u0636 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645 \u0647\u0631 \u0622\u06cc\u062a\u0645 \u0646\u0645\u0627\u062f \u06cc\u06a9 \u0633\u0641\u0627\u0631\u0634 \u0628\u0627 \u0645\u0642\u062f\u0627\u0631 \u062a\u0635\u0627\u062f\u0641\u06cc \u0628\u06cc\u0646 100 \u062a\u0627 1000 \u062f\u0644\u0627\u0631 \u0627\u0633\u062a\n const mockAmount = Math.floor(Math.random() * 900) + 100;\n totalRevenue += mockAmount;\n});\n\nconst totalCount = items.length;\nconst aov = totalCount > 0 ? (totalRevenue / totalCount).toFixed(2) : 0;\nconst today = new Date().toISOString().split('T')[0];\n\nreturn [{\n json: {\n report_date: today,\n total_revenue: totalRevenue,\n total_orders: totalCount,\n average_order_value: parseFloat(aov)\n }\n}];"
},
"id": "b2c3d4e5-3333-4444-8888-000000000003",
"name": "Code",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
400
]
},
{
"parameters": {
"operation": "upsert",
"table": {
"__rl": true,
"value": "daily_kpi",
"mode": "list",
"cachedResultName": "daily_kpi"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"report_date": "={{ $json.report_date }}",
"total_revenue": "={{ $json.total_revenue }}",
"total_orders": "={{ $json.total_orders }}",
"average_order_value": "={{ $json.average_order_value }}"
},
"matchingColumns": [
"report_date"
],
"schema": [
{
"id": "report_date",
"displayName": "report_date",
"required": false,
"defaultMatch": true,
"canBeUsedToMatch": true,
"type": "string"
},
{
"id": "total_revenue",
"displayName": "total_revenue",
"required": false,
"defaultMatch": false,
"canBeUsedToMatch": false,
"type": "number"
},
{
"id": "total_orders",
"displayName": "total_orders",
"required": false,
"defaultMatch": false,
"canBeUsedToMatch": false,
"type": "number"
},
{
"id": "average_order_value",
"displayName": "average_order_value",
"required": false,
"defaultMatch": false,
"canBeUsedToMatch": false,
"type": "number"
}
]
},
"options": {}
},
"id": "b2c3d4e5-4444-4444-8888-000000000004",
"name": "PostgreSQL",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
900,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond1",
"leftValue": "={{ $json.total_revenue }}",
"rightValue": 5000,
"operator": {
"type": "number",
"operation": "gte"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "b2c3d4e5-5555-4444-8888-000000000005",
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1120,
400
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "C0987654321",
"mode": "list",
"cachedResultName": "management-reports"
},
"text": "\ud83d\udcc8 *Daily Sales Target Achieved!*\n\n\ud83d\udcc5 *Date:* {{ $json.report_date }}\n\ud83d\udcb0 *Total Revenue:* ${{ $json.total_revenue }}\n\ud83d\uded2 *Total Orders:* {{ $json.total_orders }}\n\ud83d\udcca *Average Order Value:* ${{ $json.average_order_value }}\n\nGreat job team! \ud83d\ude80",
"otherOptions": {}
},
"id": "b2c3d4e5-6666-4444-8888-000000000006",
"name": "Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1340,
320
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Schedule": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "PostgreSQL",
"type": "main",
"index": 0
}
]
]
},
"PostgreSQL": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"IF": {
"main": [
[
{
"node": "Slack",
"type": "main",
"index": 0
}
],
[]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all"
},
"id": "22-ecommerce-etl-kpi-postgres",
"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.
postgresslackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
22-ecommerce-etl-kpi-postgres. Uses schedule, httpRequest, postgres, slack. Scheduled trigger; 6 nodes.
Source: https://github.com/kooroosh1363/agentic-automation-lab/blob/main/22-ecommerce-etl-kpi-postgres/workflow.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.
This n8n template builds an automated daily news digest powered by Claude AI.
Automates sales data analysis and strategic insight generation for sales managers and strategists needing actionable intelligence. Fetches multi-source data from sales, marketing, and financial system
Scheduled runs collect data from oil markets, global shipping movements, news sources, and official reports. The system performs statistical checks to detect anomalies and volatility shifts. An AI-dri
This workflow automates end-to-end patient care coordination by monitoring appointment schedules, clinical events, and care milestones while orchestrating personalized communications across multiple c
Business Post Pipeline. Uses postgres, httpRequest, agent, lmChatGoogleGemini. Scheduled trigger; 30 nodes.