AutomationFlowsSlack & Telegram › Telegram Hitl Approval Handler

Telegram Hitl Approval Handler

Telegram HITL Approval Handler. Uses telegramTrigger, telegram, httpRequest. Event-driven trigger; 8 nodes.

Event trigger★★★★☆ complexity8 nodesTelegram TriggerTelegramHTTP Request
Slack & Telegram Trigger: Event Nodes: 8 Complexity: ★★★★☆ Added:

This workflow follows the HTTP Request → 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 →

Download .json
{
  "name": "Telegram HITL Approval Handler",
  "nodes": [
    {
      "parameters": {
        "updates": [
          "callback_query"
        ],
        "additionalFields": {}
      },
      "id": "trigger-callback",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "notes": "One consumer per bot token. Only this trigger should listen on callback_query for this bot."
    },
    {
      "parameters": {
        "jsCode": "const cq = $input.first().json.callback_query || $input.first().json;\nconst data = cq.data || '';\nconst [decision, ...rest] = data.split(':');\nconst jobId = rest.join(':');\nconst isApprove = decision === 'APPROVE';\nconst isDeny = decision === 'DENY';\nreturn [{ json: {\n  callbackId: cq.id,\n  chatId: String(cq.message?.chat?.id || ''),\n  messageId: cq.message?.message_id,\n  messageText: cq.message?.text || cq.message?.caption || '',\n  jobId,\n  decision,\n  isApprove,\n  isDeny,\n  recognized: isApprove || isDeny\n} }];"
      },
      "id": "parse-callback",
      "name": "Parse Callback",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "notes": "Parses APPROVE:<jobId> / DENY:<jobId>."
    },
    {
      "parameters": {
        "resource": "callback",
        "operation": "answerQuery",
        "queryId": "={{ $json.callbackId }}",
        "additionalFields": {
          "text": "={{ $json.isApprove ? '\u2705 Approved' : ($json.isDeny ? '\u274c Denied' : '\u26a0\ufe0f Unrecognized') }}",
          "show_alert": false
        }
      },
      "id": "answer-callback",
      "name": "Answer Callback",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        440,
        -140
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "notes": "Must answer within ~10s or Telegram shows a spinner."
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.isApprove }}",
              "value2": true
            }
          ]
        },
        "options": {}
      },
      "id": "if-approve",
      "name": "Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        440,
        120
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.APPROVE_ACTION_URL }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { jobId: $json.jobId } }}",
        "options": {}
      },
      "id": "http-approve",
      "name": "Run Approve Action",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        680,
        40
      ],
      "notes": "POSTs { jobId } to APPROVE_ACTION_URL. Put your real action behind this URL."
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.DENY_ACTION_URL || 'https://example.com/noop' }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ { jobId: $json.jobId } }}",
        "options": {}
      },
      "id": "http-deny",
      "name": "Run Deny Action",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        680,
        200
      ],
      "onError": "continueRegularOutput",
      "notes": "Optional. Set DENY_ACTION_URL to record/cleanup on deny; otherwise this no-ops."
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "editMessageText",
        "chatId": "={{ $('Parse Callback').first().json.chatId }}",
        "messageId": "={{ $('Parse Callback').first().json.messageId }}",
        "text": "={{ $('Parse Callback').first().json.messageText + '\\n\\n\u2705 Approved \u2014 ' + $('Parse Callback').first().json.jobId }}",
        "replyMarkup": "inlineKeyboard",
        "inlineKeyboard": {
          "rows": []
        }
      },
      "id": "edit-approved",
      "name": "Edit Message (Approved)",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        900,
        40
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "notes": "Clears the inline keyboard so the action can't be repeated."
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "editMessageText",
        "chatId": "={{ $('Parse Callback').first().json.chatId }}",
        "messageId": "={{ $('Parse Callback').first().json.messageId }}",
        "text": "={{ $('Parse Callback').first().json.messageText + '\\n\\n\u274c Denied \u2014 ' + $('Parse Callback').first().json.jobId }}",
        "replyMarkup": "inlineKeyboard",
        "inlineKeyboard": {
          "rows": []
        }
      },
      "id": "edit-denied",
      "name": "Edit Message (Denied)",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        900,
        200
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Parse Callback",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Callback": {
      "main": [
        [
          {
            "node": "Answer Callback",
            "type": "main",
            "index": 0
          },
          {
            "node": "Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approved?": {
      "main": [
        [
          {
            "node": "Run Approve Action",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Run Deny Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Approve Action": {
      "main": [
        [
          {
            "node": "Edit Message (Approved)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Deny Action": {
      "main": [
        [
          {
            "node": "Edit Message (Denied)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false,
  "meta": {
    "templateCredsSetupCompleted": false
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Telegram HITL Approval Handler. Uses telegramTrigger, telegram, httpRequest. Event-driven trigger; 8 nodes.

Source: https://github.com/sitewisesoftware/n8n-telegram-hitl-handler/blob/main/workflow.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

N8N Complete Final. Uses telegramTrigger, dataTable, telegram, mqtt. Event-driven trigger; 58 nodes.

Telegram Trigger, Data Table, Telegram +3
Slack & Telegram

Pede Ai. Uses httpRequest, telegram, postgres, telegramTrigger. Event-driven trigger; 57 nodes.

HTTP Request, Telegram, Postgres +1
Slack & Telegram

TextMain. Uses telegramTrigger, stopAndError, telegram, httpRequest. Event-driven trigger; 56 nodes.

Telegram Trigger, Stop And Error, Telegram +2
Slack & Telegram

Pede Ai. Uses httpRequest, telegram, postgres, telegramTrigger. Event-driven trigger; 53 nodes.

HTTP Request, Telegram, Postgres +1
Slack & Telegram

📄 Documentation: Notion Guide

Telegram Trigger, @Blotato/N8N Nodes Blotato, Telegram +1