This workflow corresponds to n8n.io template #9039 — we link there as the canonical source.
This workflow follows the Postgres → Telegram 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": "My workflow",
"tags": [],
"nodes": [
{
"id": "411a0468-c67b-4762-93e2-1d4e116f1181",
"name": "01 Webhook Trigger: Approval Decision",
"type": "n8n-nodes-base.webhook",
"position": [
-1808,
400
],
"parameters": {
"path": "/approval",
"options": {
"responseData": "\u2705 Thanks, your decision was recorded."
}
},
"typeVersion": 2.1
},
{
"id": "08db80ea-aad6-45f7-973a-a0fbfa9285e0",
"name": "02 FN: Verify Signature + TTL",
"type": "n8n-nodes-base.code",
"position": [
-1584,
400
],
"parameters": {
"language": "python",
"pythonCode": "import hashlib\nimport hmac\nimport time\nimport os\n\nsecret = os.getenv(\"SECRET_KEY\")\nif not secret:\n raise ValueError(\"SECRET_KEY environment variable not set\")\nnow = int(time.time())\n\nout = []\n\nfor item in items:\n q = item[\"json\"].get(\"query\", {})\n cid = q.get(\"cid\")\n status = q.get(\"status\")\n action = q.get(\"action\")\n exp = int(q.get(\"exp\", \"0\"))\n sig = q.get(\"sig\")\n\n payload = f\"{cid}|{status}|{exp}\"\n check_sig = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()\n\n # Default result\n result = {\n \"correlation_id\": cid,\n \"new_status\": status,\n \"reason\": None\n }\n\n if sig != check_sig:\n result[\"action\"] = \"invalid\"\n result[\"reason\"] = \"Invalid signature\"\n elif exp < now:\n result[\"action\"] = \"expired\"\n result[\"reason\"] = \"Link expired\"\n elif action == \"approve\":\n result[\"action\"] = \"approve\"\n result[\"actor\"] = \"manager\" # later replace with real manager identity\n elif action == \"reject\":\n result[\"action\"] = \"reject\"\n result[\"actor\"] = \"manager\"\n else:\n result[\"action\"] = \"unknown\"\n result[\"reason\"] = \"Unsupported action\"\n\n out.append({\"json\": result})\n\nreturn out\n"
},
"typeVersion": 2
},
{
"id": "3b7594c2-07c0-4baa-906b-daacff925853",
"name": "04c DB: Update Ticket Status",
"type": "n8n-nodes-base.postgres",
"notes": "Updates ticket status by correlation ID. Also inserts audit row and notifies ticket owner. Requires tickets table and audit schema.",
"position": [
-896,
192
],
"parameters": {
"query": "UPDATE tickets\nSET status = $2, updated_at = NOW()\nWHERE correlation_id = $1::uuid\nRETURNING id, status, updated_at, correlation_id;\n",
"options": {
"queryReplacement": "={{$json.correlation_id}},{{$json.new_status}}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 2.6
},
{
"id": "17b6b2df-3792-4460-8f55-c32422d3ba2f",
"name": "04c1 DB: Get Ticket Owner",
"type": "n8n-nodes-base.postgres",
"position": [
-448,
192
],
"parameters": {
"query": "SELECT chat_id, correlation_id, status, subject\nFROM tickets\nWHERE correlation_id = $1::uuid;",
"options": {
"queryReplacement": "={{ $('04c DB: Update Ticket Status').item.json.correlation_id }}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "19802b0c-d66b-4a6a-b009-8d7f721abcca",
"name": "04c1a IF: Resolved or In Progress",
"type": "n8n-nodes-base.if",
"position": [
-224,
96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "115bb477-3dfa-4d9b-8e4b-cd2ef15439e1",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"status\"] }}",
"rightValue": "resolved"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "da2d1a92-a349-40ba-8160-63847c560a23",
"name": "05c1a Telegram: Notify Resolved",
"type": "n8n-nodes-base.telegram",
"notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
"position": [
224,
0
],
"parameters": {
"text": "=\ud83c\udf89 Good news! Your ticket (<code>{{ $json.correlation_id }}</code>) has been resolved. \nYou can check details anytime with: \n/status <code>{{ $json.correlation_id }}</code>",
"chatId": "={{ $json.chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1.2
},
{
"id": "e2290e2c-1572-46ac-b690-46626ede3a35",
"name": "05c1b Telegram: Notify In Progress",
"type": "n8n-nodes-base.telegram",
"notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
"position": [
224,
192
],
"parameters": {
"text": "=\ud83d\udd04 Your ticket (<code>{{ $json.correlation_id }}.</code>) is now being worked on. \nWe\u2019ll notify you once it\u2019s resolved.",
"chatId": "={{ $json.chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1.2
},
{
"id": "828e2442-5f9e-4d12-a671-57b90d49e807",
"name": "05c Telegram: Update Confirmation",
"type": "n8n-nodes-base.telegram",
"notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
"position": [
-224,
288
],
"parameters": {
"text": "=\u2705 <b>Ticket <code>{{ $json.correlation_id }}</code></b> updated!\n\ud83d\udccc <b>New Status:</b> {{ $json[\"status\"] }}\n\u23f0 <b>Updated At:</b> {{ new Date($(\"04c DB: Update Ticket Status\").item.json.updated_at).toLocaleString() }}\n",
"chatId": "={{ $json.chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1.2
},
{
"id": "7c2d91ca-0014-4d8d-97a4-bbd479274f88",
"name": "Notify Failed?",
"type": "n8n-nodes-base.if",
"position": [
448,
96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4eb644e5-1340-492e-96e7-66198d2d72ad",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ !!$json.error }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "16995a07-e4ed-4ebc-88a4-ce430ab0eee0",
"name": "Execute a SQL query",
"type": "n8n-nodes-base.postgres",
"position": [
672,
96
],
"parameters": {
"query": "INSERT INTO workflow_errors \n (workflow_id, workflow_name, execution_id, error_message, json_payload)\nVALUES \n ($1, $2, $3, $4, $5::jsonb);\n",
"options": {
"queryReplacement": "={{ $workflow.id }},\n{{ $workflow.name }},\n{{ $execution.id }},\n{{ $json.error?.message || 'unknown' }},\n{{ JSON.stringify($json) }}\n"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "1ba78ac5-24f1-4b4a-bc2b-ce8e14419884",
"name": "04c2 DB: Insert Audit Row",
"type": "n8n-nodes-base.postgres",
"position": [
-672,
192
],
"parameters": {
"query": "INSERT INTO ticket_audit\n (ticket_id, correlation_id, action, new_status, actor_chat_id)\nVALUES\n ($1, $2, 'update', $3, $4);\n",
"options": {
"queryReplacement": "={{ $json.id }},\n{{ $json.correlation_id }},\n{{ $json.status }},\n{{ $('02 FN: Verify Signature + TTL').item.json.actor }}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "d9707ad4-fe4b-4335-90ff-aeba6d90cffc",
"name": "Text (reject)",
"type": "n8n-nodes-base.telegram",
"position": [
-448,
384
],
"parameters": {
"text": "=\u274c Manager rejected update.\nTicket <code>{{ $('02 FN: Verify Signature + TTL').item.json.correlation_id }}</code> stays unchanged.",
"chatId": "chat_id",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "ccc7b9c3-107b-48cf-b52b-12e86547d378",
"name": "04r0 DB: Get Ticket ID",
"type": "n8n-nodes-base.postgres",
"position": [
-896,
384
],
"parameters": {
"query": "SELECT id, correlation_id \nFROM tickets \nWHERE correlation_id = $1::uuid;",
"options": {
"queryReplacement": "={{$json.correlation_id}}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "3e11f388-20d3-46e3-b41c-be7602b5b6bf",
"name": "Execute a SQL query1",
"type": "n8n-nodes-base.postgres",
"position": [
-672,
384
],
"parameters": {
"query": "INSERT INTO ticket_audit \n (ticket_id, correlation_id, action, new_status, actor_chat_id)\nVALUES \n ($1, $2, 'reject', $3, $4);\n",
"options": {
"queryReplacement": "={{$json.id}}, {{$json.correlation_id}}, {{ $('02 FN: Verify Signature + TTL').item.json.new_status }}, {{ $('02 FN: Verify Signature + TTL').item.json.actor }}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "6b3aedec-d739-486c-ba9a-854a87973e1c",
"name": "If Resolved",
"type": "n8n-nodes-base.if",
"position": [
0,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "dc1d552d-728a-46cd-9024-14d88b01f77f",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"status\"] }}",
"rightValue": "resolved"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "34b8c0a5-478d-4354-89f0-d053c75a9880",
"name": "If in_progress",
"type": "n8n-nodes-base.if",
"position": [
0,
192
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "a4a97bc7-96b5-4e5b-8ade-fd4f9d292016",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"status\"] }}",
"rightValue": "in_progress"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "0c522006-2356-4235-a8d9-57e0399439b9",
"name": "Actions",
"type": "n8n-nodes-base.switch",
"position": [
-1360,
368
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "approve",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "b720a50f-1e38-477b-b828-f85c8e4e10d9",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"action\"] }}",
"rightValue": "approve"
}
]
},
"renameOutput": true
},
{
"outputKey": "reject",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1f0d9637-5986-4e90-9f64-3829a12c15ef",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"action\"] }}",
"rightValue": "reject"
}
]
},
"renameOutput": true
},
{
"outputKey": "expired",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2ad38675-da19-4380-882c-0c3da132eea1",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"action\"] }}",
"rightValue": "expired"
}
]
},
"renameOutput": true
},
{
"outputKey": "invalid",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "74c8e5cd-1441-43ef-bf17-98956cf7e63c",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json[\"action\"] }}",
"rightValue": "invalid"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "5a1ead63-50e5-4740-8a62-6d8390496901",
"name": "04e DB: Insert Audit Expired",
"type": "n8n-nodes-base.postgres",
"position": [
-896,
576
],
"parameters": {
"query": "INSERT INTO ticket_audit\n (correlation_id, action, new_status, actor_chat_id)\nVALUES\n ($1, 'expired', $2, 'system');\n",
"options": {
"queryReplacement": "={{ $json.correlation_id }}, {{ $json.new_status }}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "ca421ae6-3163-410d-bf0d-a4896adc16fa",
"name": "04i DB: Insert Audit Invalid",
"type": "n8n-nodes-base.postgres",
"position": [
-896,
768
],
"parameters": {
"query": "INSERT INTO ticket_audit\n (correlation_id, action, new_status, actor_chat_id)\nVALUES\n ($1, 'invalid', $2, 'system');\n",
"options": {
"queryReplacement": "={{ $json.correlation_id }}, {{ $json.new_status }}"
},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "553fa208-5f0c-4a79-aeed-5e03477ad32a",
"name": "05e Telegram: Notify Expired",
"type": "n8n-nodes-base.telegram",
"position": [
-672,
576
],
"parameters": {
"text": "=\u23f0 Manager notice: approval link expired for ticket <code>{{ $('02 FN: Verify Signature + TTL').item.json.correlation_id }}</code>.",
"chatId": "chat_id",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "00c9e4e8-3b06-4df5-a2b6-3d831084ac45",
"name": "05i Telegram: Alert Invalid",
"type": "n8n-nodes-base.telegram",
"position": [
-672,
768
],
"parameters": {
"text": "=\ud83d\udea8 Invalid approval attempt detected.\nTicket: <code>{{ $('02 FN: Verify Signature + TTL').item.json.correlation_id }}</code>",
"chatId": "chat_id",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "625211e5-1974-43b0-9855-1ce71577e3f3",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4272,
256
],
"parameters": {
"width": 832,
"height": 576,
"content": "## \ud83d\uded1 Human-in-the-Loop Approval Flow (n8n + Postgres + Telegram)\n\nThis workflow adds a secure approval step into your automations. \nManagers receive signed approval/reject links in Telegram. \nLinks expire after TTL, and every action is logged in Postgres.\n\n### \u2728 Features\n- HMAC signed approval links with TTL \n- Status updates via Telegram \n- Audit table in Postgres \n- Auto-expiry handling \n\n### \ud83d\udcd2 Requirements\n- n8n instance \n- Postgres with `tickets` + `approvals` tables \n- Telegram bot token \n- One secret key set in env (`SECRET_KEY`) \n\n### \u2699\ufe0f Setup\n1. Import workflow JSON \n2. Create audit table (SQL provided) \n3. Configure `.env` (DB, Telegram, SECRET_KEY) \n4. Run a test ticket \n"
},
"typeVersion": 1
},
{
"id": "fb72674c-6184-4754-9c02-61a9382764d4",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1664,
160
],
"parameters": {
"color": 5,
"height": 224,
"content": "### \ud83d\udd10 Security Note\nThis Code node requires `SECRET_KEY` to be set as an environment variable. \nThe workflow will fail if it\u2019s missing \u2014 this is intentional for security. \nAdd `SECRET_KEY=your-secret` to your `.env`.\n"
},
"typeVersion": 1
},
{
"id": "a87e7f7c-ed16-47db-a3ff-f634c8fcc999",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
576
],
"parameters": {
"color": 4,
"height": 256,
"content": "### \ud83d\udcf2 Telegram Chat IDs\n- User-facing nodes use `={{ $json.chat_id }}` pulled from the ticket. \n- Manager/admin alerts (e.g., invalid attempts) may use fixed IDs or env vars. \nUpdate these values to your actual team setup.\n"
},
"typeVersion": 1
},
{
"id": "c1f22f77-f5b9-4b70-ae85-e49cbe888894",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2144,
368
],
"parameters": {
"height": 304,
"content": "### \ud83d\udd11 Generate Approval Links\n- Code node creates signed URLs \n- Uses HMAC with secret key \n- Adds expiry timestamp (TTL) \n### \u2705 Verify Link & TTL\n- Validates HMAC signature \n- Checks expiry timestamp \n- Rejects invalid or expired clicks \n"
},
"typeVersion": 1
},
{
"id": "5c439394-3545-4abb-a65b-0fecbe36a979",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3392,
256
],
"parameters": {
"color": 5,
"width": 1168,
"height": 1568,
"content": "## \ud83d\udee0 Step-by-Step Setup (Beginner Friendly)\n\n1. **Set environment variable** \n - Open your `.env` file (or environment config in your server). \n - Add: \n ```\n SECRET_KEY=mysecretkey\n ``` \n - Restart n8n so it picks up the new variable.\n\n2. **Create Postgres tables** (run these in order):\n - **Tickets** \n ```sql\n CREATE TABLE tickets (\n id BIGSERIAL PRIMARY KEY,\n correlation_id UUID,\n status TEXT,\n subject TEXT,\n chat_id TEXT,\n updated_at TIMESTAMP DEFAULT NOW()\n );\n ```\n - **Audit log** \n ```sql\n CREATE TABLE ticket_audit (\n id BIGSERIAL PRIMARY KEY,\n ticket_id BIGINT,\n correlation_id UUID,\n action TEXT,\n new_status TEXT,\n actor_chat_id TEXT,\n created_at TIMESTAMP DEFAULT NOW()\n );\n ```\n - **Workflow errors** \n ```sql\n CREATE TABLE workflow_errors (\n id BIGSERIAL PRIMARY KEY,\n workflow_id TEXT,\n workflow_name TEXT,\n execution_id TEXT,\n error_message TEXT,\n json_payload JSONB,\n created_at TIMESTAMP DEFAULT NOW()\n );\n ```\n\n3. **Add credentials in n8n** \n - Go to *Credentials \u2192 Telegram API* \u2192 paste your bot token. \n - Go to *Credentials \u2192 Postgres* \u2192 add DB connection details. \n - **Important:** Replace `chat_id` placeholders in Telegram nodes with your real Telegram ID (use `@userinfobot` in Telegram to get it).\n\n4. **Import the workflow JSON** \n - Click *Import workflow* in n8n. \n - Select this file. \n - Save and activate.\n\n5. **Test an approval link** \n - Open a URL like this in your browser (replace with your own values): \n ```\n http://YOUR_N8N_HOST/approval?cid=<UUID>&status=in_progress&action=approve&exp=1735939200&sig=<hmac-signature>\n ``` \n - `cid` \u2192 ticket correlation ID from your DB \n - `status` \u2192 `resolved` or `in_progress` \n - `action` \u2192 `approve` or `reject` \n - `exp` \u2192 expiry time in epoch seconds \n - `sig` \u2192 HMAC-SHA256 signature of `cid|status|exp` \n\n6. **Verify it works** \n - Ticket status changes in the `tickets` table. \n - Row is added to `ticket_audit`. \n - Telegram sends a notification. \n - If the link is invalid/expired, you get an alert and it\u2019s logged in `workflow_errors`.\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "",
"connections": {
"Actions": {
"main": [
[
{
"node": "04c DB: Update Ticket Status",
"type": "main",
"index": 0
}
],
[
{
"node": "04r0 DB: Get Ticket ID",
"type": "main",
"index": 0
}
],
[
{
"node": "04e DB: Insert Audit Expired",
"type": "main",
"index": 0
}
],
[
{
"node": "04i DB: Insert Audit Invalid",
"type": "main",
"index": 0
}
]
]
},
"If Resolved": {
"main": [
[
{
"node": "05c1a Telegram: Notify Resolved",
"type": "main",
"index": 0
}
]
]
},
"If in_progress": {
"main": [
[
{
"node": "05c1b Telegram: Notify In Progress",
"type": "main",
"index": 0
}
]
]
},
"Notify Failed?": {
"main": [
[
{
"node": "Execute a SQL query",
"type": "main",
"index": 0
}
]
]
},
"Execute a SQL query1": {
"main": [
[
{
"node": "Text (reject)",
"type": "main",
"index": 0
}
]
]
},
"04r0 DB: Get Ticket ID": {
"main": [
[
{
"node": "Execute a SQL query1",
"type": "main",
"index": 0
}
]
]
},
"04c1 DB: Get Ticket Owner": {
"main": [
[
{
"node": "04c1a IF: Resolved or In Progress",
"type": "main",
"index": 0
},
{
"node": "05c Telegram: Update Confirmation",
"type": "main",
"index": 0
}
]
]
},
"04c2 DB: Insert Audit Row": {
"main": [
[
{
"node": "04c1 DB: Get Ticket Owner",
"type": "main",
"index": 0
}
]
]
},
"04c DB: Update Ticket Status": {
"main": [
[
{
"node": "04c2 DB: Insert Audit Row",
"type": "main",
"index": 0
}
]
]
},
"04e DB: Insert Audit Expired": {
"main": [
[
{
"node": "05e Telegram: Notify Expired",
"type": "main",
"index": 0
}
]
]
},
"04i DB: Insert Audit Invalid": {
"main": [
[
{
"node": "05i Telegram: Alert Invalid",
"type": "main",
"index": 0
}
]
]
},
"02 FN: Verify Signature + TTL": {
"main": [
[
{
"node": "Actions",
"type": "main",
"index": 0
}
]
]
},
"05c1a Telegram: Notify Resolved": {
"main": [
[
{
"node": "Notify Failed?",
"type": "main",
"index": 0
}
]
]
},
"04c1a IF: Resolved or In Progress": {
"main": [
[
{
"node": "If Resolved",
"type": "main",
"index": 0
}
],
[
{
"node": "If in_progress",
"type": "main",
"index": 0
}
]
]
},
"05c1b Telegram: Notify In Progress": {
"main": [
[
{
"node": "Notify Failed?",
"type": "main",
"index": 0
}
]
]
},
"01 Webhook Trigger: Approval Decision": {
"main": [
[
{
"node": "02 FN: Verify Signature + TTL",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
postgrestelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Teams that need a manager approval step before a ticket or request can change status. Great for internal ops, IT requests, or any workflow where “a human must sign off.” 📨 Manager receives approval/reject link 🔑 Link is signed with HMAC + expiry (secure & tamper-proof) 🗄️…
Source: https://n8n.io/workflows/9039/ — 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 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
Pede Ai. Uses httpRequest, telegram, postgres, telegramTrigger. Event-driven trigger; 53 nodes.
qualiopi. Uses airtable, telegram, emailSend, httpRequest. Webhook trigger; 51 nodes.
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
News Digest Bot - Multi-User (Postgres). Uses telegramTrigger, postgres, telegram, rssFeedRead. Event-driven trigger; 45 nodes.