This workflow follows the Postgres → Slack 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": "Webhook Logger",
"nodes": [
{
"parameters": {
"path": "webhook",
"options": {}
},
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "// Process webhook data\nconst webhookData = $input.first().json;\nconst headers = $input.first().headers;\nconst query = $input.first().query;\n\nconst processed = {\n // Basic webhook info\n timestamp: new Date().toISOString(),\n method: headers['x-http-method'] || 'POST',\n contentType: headers['content-type'] || 'application/json',\n userAgent: headers['user-agent'] || 'Unknown',\n ipAddress: headers['x-forwarded-for'] || headers['x-real-ip'] || 'Unknown',\n \n // Request data\n body: webhookData,\n query: query,\n headers: headers,\n \n // Calculated fields\n bodySize: JSON.stringify(webhookData).length,\n hasQuery: Object.keys(query || {}).length > 0,\n isJson: (headers['content-type'] || '').includes('application/json'),\n \n // Extract common fields if they exist\n eventType: webhookData.event || webhookData.type || 'unknown',\n source: webhookData.source || webhookData.origin || 'unknown',\n id: webhookData.id || webhookData.uuid || null,\n \n // Timestamp from webhook if available\n webhookTimestamp: webhookData.timestamp || webhookData.created_at || null\n};\n\nreturn { json: processed };"
},
"id": "process-webhook",
"name": "Process Webhook Data",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"operation": "insert",
"table": "webhook_logs",
"columns": "timestamp, method, content_type, user_agent, ip_address, body_size, has_query, is_json, event_type, source, webhook_id, webhook_timestamp",
"values": "={{ $json.timestamp }}, {{ $json.method }}, {{ $json.contentType }}, {{ $json.userAgent }}, {{ $json.ipAddress }}, {{ $json.bodySize }}, {{ $json.hasQuery }}, {{ $json.isJson }}, {{ $json.eventType }}, {{ $json.source }}, {{ $json.id }}, {{ $json.webhookTimestamp }}"
},
"id": "save-webhook-log",
"name": "Save Webhook Log",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
680,
200
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "insert",
"table": "webhook_events",
"columns": "timestamp, event_type, source, webhook_id, data",
"values": "={{ $json.timestamp }}, {{ $json.eventType }}, {{ $json.source }}, {{ $json.id }}, {{ JSON.stringify($json.body) }}"
},
"id": "save-webhook-event",
"name": "Save Webhook Event",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
680,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Calculate webhook metrics\nconst webhookData = $input.first().json;\n\nconst metrics = {\n timestamp: webhookData.timestamp,\n eventType: webhookData.eventType,\n source: webhookData.source,\n bodySize: webhookData.bodySize,\n processingTime: Date.now() - new Date(webhookData.timestamp).getTime(),\n isRecent: new Date(webhookData.timestamp) > new Date(Date.now() - 5 * 60 * 1000), // Last 5 minutes\n hasId: !!webhookData.id,\n hasTimestamp: !!webhookData.webhookTimestamp\n};\n\nreturn { json: metrics };"
},
"id": "calculate-metrics",
"name": "Calculate Metrics",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"operation": "insert",
"table": "webhook_metrics",
"columns": "timestamp, event_type, source, body_size, processing_time, is_recent, has_id, has_timestamp",
"values": "={{ $json.timestamp }}, {{ $json.eventType }}, {{ $json.source }}, {{ $json.bodySize }}, {{ $json.processingTime }}, {{ $json.isRecent }}, {{ $json.hasId }}, {{ $json.hasTimestamp }}"
},
"id": "save-metrics",
"name": "Save Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
1120,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "n8n",
"mode": "name"
},
"text": "\ud83d\udce5 Webhook Received",
"otherOptions": {
"attachments": [
{
"color": "good",
"fields": [
{
"title": "Event Type",
"value": "{{ $json.eventType }}",
"short": true
},
{
"title": "Source",
"value": "{{ $json.source }}",
"short": true
},
{
"title": "Body Size",
"value": "{{ $json.bodySize }} bytes",
"short": true
},
{
"title": "Processing Time",
"value": "{{ $json.processingTime }}ms",
"short": true
},
{
"title": "IP Address",
"value": "{{ $json.ipAddress }}",
"short": true
},
{
"title": "User Agent",
"value": "{{ $json.userAgent }}",
"short": true
}
]
}
]
}
},
"id": "slack-notification",
"name": "Slack Notification",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
1340,
300
],
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'success', message: 'Webhook received and processed', timestamp: $json.timestamp, eventType: $json.eventType }) }}"
},
"id": "webhook-response",
"name": "Webhook Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1560,
300
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Process Webhook Data",
"type": "main",
"index": 0
}
]
]
},
"Process Webhook Data": {
"main": [
[
{
"node": "Save Webhook Log",
"type": "main",
"index": 0
},
{
"node": "Save Webhook Event",
"type": "main",
"index": 0
},
{
"node": "Calculate Metrics",
"type": "main",
"index": 0
}
]
]
},
"Calculate Metrics": {
"main": [
[
{
"node": "Save Metrics",
"type": "main",
"index": 0
}
]
]
},
"Save Metrics": {
"main": [
[
{
"node": "Slack Notification",
"type": "main",
"index": 0
}
]
]
},
"Slack Notification": {
"main": [
[
{
"node": "Webhook Response",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"id": "webhook",
"name": "webhook"
}
],
"triggerCount": 1,
"updatedAt": "2024-01-01T00:00:00.000Z",
"versionId": "1"
}
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
Webhook Logger. Uses postgres, slack. Webhook trigger; 8 nodes.
Source: https://github.com/kyletaylored/n8n-docker-demo/blob/84bda45802ceaf2a5ac14b7d45606f1d78cb750b/examples/n8n-demo/workflows/05-webhook-logger.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 workflow automates end-to-end research analysis by coordinating multiple AI models—including NVIDIA NIM (Llama), OpenAI GPT-4, and Claude to analyze uploaded documents, extract insights, and gene
This n8n workflow automates task creation and scheduled reminders for users via a Telegram bot, ensuring timely notifications across multiple channels like email and Slack. It streamlines task managem
This workflow exposes a single webhook that either accepts new approval requests or handles Slack button callbacks, posting interactive Slack Block Kit messages and recording decisions in a PostgreSQL
QA Platform — Jira Story to Test Workflow. Uses jiraTrigger, postgres, httpRequest, slack. Webhook trigger; 20 nodes.
Automação de Chargeback - Contestação SaaS. Uses httpRequest, postgres, emailSend, slack. Webhook trigger; 14 nodes.