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": "WF-005-asset-approval-gate",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "telegram-approval",
"responseMode": "onReceived",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000001",
"name": "Telegram Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
400
]
},
{
"parameters": {
"jsCode": "const b = $input.item.json.body || {};\nif (b.callback_query) {\n const cq = b.callback_query;\n const m = String(cq.data || '').match(/^(approve|reject)_(\\d+)$/);\n return [{ json: {\n kind: m ? 'callback' : 'other',\n action: m ? m[1] : null,\n asset_id: m ? Number(m[2]) : null,\n callback_query_id: cq.id,\n chat_id: cq.message && cq.message.chat && cq.message.chat.id\n } }];\n}\nif (b.message && b.message.reply_to_message) {\n const rm = b.message.reply_to_message.text || '';\n const m = rm.match(/asset #(\\d+)/);\n return [{ json: {\n kind: m ? 'reject_reason' : 'other',\n asset_id: m ? Number(m[1]) : null,\n reason: b.message.text || '',\n chat_id: b.message.chat && b.message.chat.id\n } }];\n}\nreturn [{ json: { kind: 'other' } }];"
},
"id": "c50500000-0005-0005-0005-000000000002",
"name": "Route Update",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
400
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.kind }}",
"rightValue": "callback",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "callback"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.kind }}",
"rightValue": "reject_reason",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "reject_reason"
}
]
},
"options": {
"fallbackOutput": "none"
}
},
"id": "c50500000-0005-0005-0005-000000000003",
"name": "Switch Update Type",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
680,
400
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/answerCallbackQuery",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "callback_query_id",
"value": "={{ $json.callback_query_id }}"
}
]
},
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000004",
"name": "Answer Callback Query",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
900,
300
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $('Route Update').item.json.action }}",
"rightValue": "approve",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "approve"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $('Route Update').item.json.action }}",
"rightValue": "reject",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "reject"
}
]
},
"options": {
"fallbackOutput": "none"
}
},
"id": "c50500000-0005-0005-0005-000000000005",
"name": "Switch Action",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
1120,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE content_assets SET status = 'approved', approved_at = NOW() WHERE id = {{ $('Route Update').item.json.asset_id }} RETURNING id, topic_id",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000006",
"name": "Approve Asset",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1340,
200
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $('Route Update').item.json.chat_id }}"
},
{
"name": "text",
"value": "=Asset approved. Scripts will be generated."
}
]
},
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000007",
"name": "Send Approve Confirmation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
200
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-005-asset-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ asset_id: $('Route Update').item.json.asset_id, action: 'approve' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000008",
"name": "Log Approve",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1780,
200
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $('Route Update').item.json.chat_id }}"
},
{
"name": "text",
"value": "=Reply to this message with the rejection reason for asset #{{ $('Route Update').item.json.asset_id }}:"
},
{
"name": "reply_markup",
"value": "={{ JSON.stringify({ force_reply: true }) }}"
}
]
},
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000009",
"name": "Ask Rejection Reason",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1340,
400
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-005-asset-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ asset_id: $('Route Update').item.json.asset_id, action: 'reject_prompted' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000010",
"name": "Log Reject Prompt",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1560,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE content_assets SET status = 'rejected', rejection_reason = '{{ String($('Route Update').item.json.reason || '').replace(/'/g, \"''\") }}' WHERE id = {{ $('Route Update').item.json.asset_id }} RETURNING id",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000011",
"name": "Reject Asset",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
900,
550
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "={{ $('Route Update').item.json.chat_id }}"
},
{
"name": "text",
"value": "=Asset #{{ $('Route Update').item.json.asset_id }} rejected. Reason recorded."
}
]
},
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000012",
"name": "Send Reject Confirmation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1120,
550
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-005-asset-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ asset_id: $('Route Update').item.json.asset_id, action: 'reject' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c50500000-0005-0005-0005-000000000013",
"name": "Log Reject",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1340,
550
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Telegram Webhook": {
"main": [
[
{
"node": "Route Update",
"type": "main",
"index": 0
}
]
]
},
"Route Update": {
"main": [
[
{
"node": "Switch Update Type",
"type": "main",
"index": 0
}
]
]
},
"Switch Update Type": {
"main": [
[
{
"node": "Answer Callback Query",
"type": "main",
"index": 0
}
],
[
{
"node": "Reject Asset",
"type": "main",
"index": 0
}
]
]
},
"Answer Callback Query": {
"main": [
[
{
"node": "Switch Action",
"type": "main",
"index": 0
}
]
]
},
"Switch Action": {
"main": [
[
{
"node": "Approve Asset",
"type": "main",
"index": 0
}
],
[
{
"node": "Ask Rejection Reason",
"type": "main",
"index": 0
}
]
]
},
"Approve Asset": {
"main": [
[
{
"node": "Send Approve Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Send Approve Confirmation": {
"main": [
[
{
"node": "Log Approve",
"type": "main",
"index": 0
}
]
]
},
"Ask Rejection Reason": {
"main": [
[
{
"node": "Log Reject Prompt",
"type": "main",
"index": 0
}
]
]
},
"Reject Asset": {
"main": [
[
{
"node": "Send Reject Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Send Reject Confirmation": {
"main": [
[
{
"node": "Log Reject",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"id": "wf005-asset-approval-gate-000000"
}
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
WF-005-asset-approval-gate. Uses httpRequest, postgres. Webhook trigger; 13 nodes.
Source: https://github.com/navin-labs/content-factory-os/blob/main/n8n/workflows/main/WF-005-asset-approval-gate.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.