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 →
{
"id": "wf008-media-approval-gate-000000",
"name": "WF-008-media-approval-gate",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "video-approval",
"responseMode": "onReceived",
"options": {}
},
"id": "c80800000-0008-0008-0008-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(/^(vapprove|vreject)_(\\d+)$/);\n return [{ json: {\n kind: m ? 'callback' : 'other',\n action: m ? (m[1] === 'vapprove' ? 'approve' : 'reject') : null,\n record_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(/publishing record #(\\d+)/);\n return [{ json: {\n kind: m ? 'reject_reason' : 'other',\n record_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": "c80800000-0008-0008-0008-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": "c80800000-0008-0008-0008-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": "c80800000-0008-0008-0008-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": "c80800000-0008-0008-0008-000000000005",
"name": "Switch Action",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
1120,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE publishing_records SET status = 'approved', approved_at = NOW() WHERE id = {{ $('Route Update').item.json.record_id }} RETURNING id, asset_id",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000006",
"name": "Approve Publishing Record",
"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": "=Video approved. Scheduling for publish."
}
]
},
"options": {}
},
"id": "c80800000-0008-0008-0008-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-008-media-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ record_id: $('Route Update').item.json.record_id, action: 'approve' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000008",
"name": "Log Approve",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1780,
200
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE publishing_records SET status = 'failed' WHERE id = {{ $('Route Update').item.json.record_id }} RETURNING id, asset_id",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000009",
"name": "Fail Publishing Record",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1340,
400
],
"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 publishing record #{{ $('Route Update').item.json.record_id }}:"
},
{
"name": "reply_markup",
"value": "={{ JSON.stringify({ force_reply: true }) }}"
}
]
},
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000010",
"name": "Ask Rejection Reason",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
400
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-008-media-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ record_id: $('Route Update').item.json.record_id, action: 'reject' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000011",
"name": "Log Reject",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1780,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE publishing_records SET rejection_reason = '{{ String($json.reason || '').replace(/'/g, \"''\") }}' WHERE id = {{ $json.record_id }} RETURNING id",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000012",
"name": "Update Rejection Reason",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
900,
550
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-008-media-approval-gate', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ record_id: $('Route Update').item.json.record_id, action: 'reject_reason' }) }}'::jsonb, '{}'::jsonb)",
"options": {}
},
"id": "c80800000-0008-0008-0008-000000000013",
"name": "Log Reject Reason",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1120,
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": "Update Rejection Reason",
"type": "main",
"index": 0
}
]
]
},
"Update Rejection Reason": {
"main": [
[
{
"node": "Log Reject Reason",
"type": "main",
"index": 0
}
]
]
},
"Answer Callback Query": {
"main": [
[
{
"node": "Switch Action",
"type": "main",
"index": 0
}
]
]
},
"Switch Action": {
"main": [
[
{
"node": "Approve Publishing Record",
"type": "main",
"index": 0
}
],
[
{
"node": "Fail Publishing Record",
"type": "main",
"index": 0
}
]
]
},
"Approve Publishing Record": {
"main": [
[
{
"node": "Send Approve Confirmation",
"type": "main",
"index": 0
}
]
]
},
"Send Approve Confirmation": {
"main": [
[
{
"node": "Log Approve",
"type": "main",
"index": 0
}
]
]
},
"Fail Publishing Record": {
"main": [
[
{
"node": "Ask Rejection Reason",
"type": "main",
"index": 0
}
]
]
},
"Ask Rejection Reason": {
"main": [
[
{
"node": "Log Reject",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
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-008-media-approval-gate. Uses httpRequest, postgres. Webhook trigger; 13 nodes.
Source: https://github.com/navin-labs/content-factory-os/blob/main/n8n/workflows/main/WF-008-media-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.