{
  "name": "Telegram Comms (Polls & Messages to Group Topics)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "send-telegram",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "node-webhook",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -880,
        128
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-bot-token",
              "name": "telegram_bot_token",
              "value": "YOUR_TELEGRAM_BOT_TOKEN",
              "type": "string"
            },
            {
              "id": "cfg-group-id",
              "name": "group_chat_id",
              "value": "YOUR_TELEGRAM_GROUP_CHAT_ID",
              "type": "string"
            },
            {
              "id": "cfg-app-url",
              "name": "app_url",
              "value": "https://YOUR_APP_DOMAIN",
              "type": "string"
            },
            {
              "id": "cfg-secret",
              "name": "webhook_secret",
              "value": "YOUR_WEBHOOK_SECRET",
              "type": "string"
            },
            {
              "id": "cfg-supabase-url",
              "name": "supabase_url",
              "value": "YOUR_SUPABASE_URL",
              "type": "string"
            },
            {
              "id": "cfg-supabase-key",
              "name": "supabase_service_key",
              "value": "YOUR_SUPABASE_SERVICE_KEY",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "node-config",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -656,
        128
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $('Webhook').item.json;\nconst body = data.body || data;\nconst secret = body.webhookSecret;\nconst expected = $('Config').item.json.webhook_secret;\nif (secret !== expected) { throw new Error('Invalid webhook secret'); }\nconst { action, content, topicId, teamId, pollQuestion, pollOptions, isAnonymous, targetGroup, ageGroup } = body;\nif (!action) throw new Error('Missing required field: action');\nreturn { json: { action: action || 'send_message', content: content || '', topicId: topicId || null, teamId: teamId || null, pollQuestion: pollQuestion || '', pollOptions: pollOptions || [], isAnonymous: isAnonymous === true, targetGroup: targetGroup || 'all', ageGroup: ageGroup || null } };"
      },
      "id": "node-validate",
      "name": "Validate & Parse",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -448,
        128
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "conditions": [
            {
              "id": "check-team-lookup",
              "leftValue": "={{ $json.teamId }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ]
        },
        "options": {}
      },
      "id": "node-need-lookup",
      "name": "Need Topic Lookup?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -224,
        128
      ]
    },
    {
      "parameters": {
        "url": "={{ $('Config').item.json.supabase_url }}/rest/v1/Team?id=eq.{{ $('Validate & Parse').item.json.teamId }}&select=telegramTopicId",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "apikey",
              "value": "={{ $('Config').item.json.supabase_service_key }}"
            },
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Config').item.json.supabase_service_key }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "node-fetch-topic",
      "name": "Fetch Team Topic ID",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        0,
        0
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "const parsed = $('Validate & Parse').item.json;\nconst config = $('Config').item.json;\n\nlet resolvedTopicId = parsed.topicId;\n\ntry {\n  const teamData = $('Fetch Team Topic ID').item.json;\n  const rows = Array.isArray(teamData) ? teamData : [teamData];\n  if (rows.length > 0 && rows[0].telegramTopicId) {\n    resolvedTopicId = rows[0].telegramTopicId;\n  }\n} catch (e) {\n  // No team data \u2014 use direct topicId or null\n}\n\nreturn {\n  json: {\n    ...parsed,\n    resolvedTopicId: resolvedTopicId ? Number(resolvedTopicId) : null,\n    chatId: config.group_chat_id\n  }\n};"
      },
      "id": "node-resolve",
      "name": "Resolve Topic",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        224,
        128
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "check-poll",
              "leftValue": "={{ $json.action }}",
              "rightValue": "send_poll",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "node-is-poll",
      "name": "Is Poll?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        448,
        128
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendPoll",
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ JSON.stringify({ chat_id: $json.chatId, question: $json.pollQuestion, options: ($json.pollOptions || ['Attending \u2705', 'Not Available \u274c', 'Maybe \ud83e\udd14']).map(function(t) { return { text: t }; }), is_anonymous: $json.isAnonymous, message_thread_id: $json.resolvedTopicId || undefined }) }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "node-send-poll",
      "name": "Send Poll",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        672,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendMessage",
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ JSON.stringify({ chat_id: $json.chatId, text: $json.content, parse_mode: 'HTML', message_thread_id: $json.resolvedTopicId || undefined }) }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "node-send-msg",
      "name": "Send Message",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        672,
        240
      ]
    },
    {
      "parameters": {
        "jsCode": "const result = $input.item.json;\nconst ok = result.ok === true;\n\nreturn {\n  json: {\n    success: ok,\n    messageId: ok ? result.result?.message_id : null,\n    error: ok ? null : (result.description || 'Telegram API error')\n  }\n};"
      },
      "id": "node-format-resp",
      "name": "Format Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        128
      ]
    },
    {
      "parameters": {},
      "id": "node-ratelimit",
      "name": "Rate Limit \u2014 1s",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1088,
        128
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Validate & Parse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate & Parse": {
      "main": [
        [
          {
            "node": "Need Topic Lookup?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Need Topic Lookup?": {
      "main": [
        [
          {
            "node": "Fetch Team Topic ID",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Resolve Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Team Topic ID": {
      "main": [
        [
          {
            "node": "Resolve Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolve Topic": {
      "main": [
        [
          {
            "node": "Is Poll?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Poll?": {
      "main": [
        [
          {
            "node": "Send Poll",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Poll": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Message": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Response": {
      "main": [
        [
          {
            "node": "Rate Limit \u2014 1s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "Telegram"
    },
    {
      "name": "Communications"
    }
  ]
}