{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "0d7bebe5-8f7c-48d1-805a-927919fd842e",
      "name": "01 Telegram Trigger: Intake + Status",
      "type": "n8n-nodes-base.telegramTrigger",
      "notes": "Listens for Telegram bot messages. Routes commands like /start, /new, /status, /update, /list into the Switch node.",
      "position": [
        -352,
        -48
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "096e115e-a27c-486e-93ce-40c23bce1b3d",
      "name": "02 Switch: Route by Command",
      "type": "n8n-nodes-base.switch",
      "notes": "Splits incoming commands into different branches. Output keys = command names (/new, /status, etc.). Fallback = Invalid Command.",
      "position": [
        -96,
        -80
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "/start",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "ce357ab4-c67e-4bf7-b791-9f90b568aa28",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json[\"message\"][\"text\"].split(\" \")[0].toLowerCase() }}",
                    "rightValue": "/start"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "/status",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "5c875ce6-1a63-42bc-b828-426e56fedd7d",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $json[\"message\"][\"text\"].split(\" \")[0].toLowerCase() }}",
                    "rightValue": "/status"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "/new",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "db0d9d53-1fa2-4b95-b4ed-026ea97ac21f",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $json[\"message\"][\"text\"].split(\" \")[0].toLowerCase() }}",
                    "rightValue": "/new"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "/update",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "54b2e9fb-1cd5-4634-a7e9-d29c936d0f9d",
                    "operator": {
                      "type": "string",
                      "operation": "startsWith"
                    },
                    "leftValue": "={{ $json[\"message\"][\"text\"].split(\" \")[0].toLowerCase() }}",
                    "rightValue": "/update"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "/list",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "1c4a4f1b-1f99-4a5d-93d3-48887d112dc2",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json[\"message\"][\"text\"].split(\" \")[0].toLowerCase() }}",
                    "rightValue": "/list"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.2
    },
    {
      "id": "7cdd210c-6bba-4f38-86af-a15b3e6417ff",
      "name": "03a FN: Normalize + Hash",
      "type": "n8n-nodes-base.code",
      "notes": "Parses ticket info from freeform Telegram text (Name, Email, Phone, Subject, Description). Generates correlation ID (UUID) and dedupe key (SHA-256 hash of email+subject).",
      "position": [
        208,
        -160
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import re\nimport hashlib\nimport uuid\n\n# Get the first incoming item\nitem = items[0]\n\n# Correct path to Telegram text\ntext = item[\"json\"].get(\"message\", {}).get(\"text\", \"\")\n\n# Defaults\nparsed = {\n    \"requester_name\": \"Unknown\",\n    \"requester_email\": \"user@example.com\",\n    \"requester_phone\": \"N/A\",\n    \"subject\": \"No subject\",\n    \"description\": \"No description\",\n    \"source\": \"telegram\",\n    \"priority\": \"normal\",\n    \"status\": \"new\",        # added here instead of in query\n    \"external_id\": None\n}\n\n# Regex patterns\npatterns = {\n    \"requester_name\": r\"Name:\\s*(.+)\",\n    \"requester_email\": r\"Email:\\s*(\\S+)\",\n    \"requester_phone\": r\"Phone:\\s*(.+)\",\n    \"subject\": r\"Subject:\\s*(.+)\",\n    \"description\": r\"Description:\\s*(.+)\"\n}\n\nfor key, pattern in patterns.items():\n    match = re.search(pattern, text, re.IGNORECASE | re.MULTILINE)\n    if match:\n        parsed[key] = match.group(1).strip()\n\n# Correlation ID\nparsed[\"correlation_id\"] = str(uuid.uuid4())\n\n# Build dedupe key\ndedupe_source = f\"{parsed['requester_email']}|{parsed['subject']}\"\nparsed[\"dedupe_key\"] = hashlib.sha256(dedupe_source.encode()).hexdigest()\n\n# External ID from Telegram chat\nchat_id = item[\"json\"].get(\"message\", {}).get(\"chat\", {}).get(\"id\")\nparsed[\"external_id\"] = str(chat_id) if chat_id else \"N/A\"\n\n# Output in correct n8n format\nreturn [{\"json\": parsed}]\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1c6e1fe9-f919-4614-a0e4-9c7a875ce7d0",
      "name": "04a DB: Upsert Ticket",
      "type": "n8n-nodes-base.postgres",
      "notes": "Executes stored Postgres function upsert_ticket. Inserts or updates a ticket record with parsed fields. Requires function to exist in DB. \ncorrelation_id, source, external_id, requester_*, subject, description, status, priority, dedupe_key\nOutput: ticket ID and correlation ID",
      "position": [
        528,
        -160
      ],
      "parameters": {
        "query": "SELECT id, correlation_id, chat_id\nFROM upsert_ticket(\n  $1::uuid,\n  $2::text,\n  $3::text,\n  $4::text,\n  $5::text,\n  $6::text,\n  $7::text,\n  $8::text,\n  $9::text,\n  $10::text,\n  $11::text,\n  $12::text\n);\n",
        "options": {
          "queryReplacement": "={{$json.correlation_id}}\n\n{{$json.source}}\n\n{{$json.external_id}}\n\n{{$json.requester_name}}\n\n{{$json.requester_email}}\n\n{{$json.requester_phone}}\n\n{{$json.subject}}\n\n{{$json.description}}\n\n{{$json.status}}\n\n{{$json.priority}}\n\n{{$json.dedupe_key}}\n\n{{ $json.external_id }}",
          "replaceEmptyStrings": true
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.6
    },
    {
      "id": "4f742ec0-aca7-4f7b-923c-4b02babef11b",
      "name": "05a Telegram Ack",
      "type": "n8n-nodes-base.telegram",
      "notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
      "position": [
        880,
        -160
      ],
      "parameters": {
        "text": "=Ticket received \u2705\nCorrelation ID: <code>{{ $json.correlation_id }}</code>\nSave this ID to check status later.\n",
        "chatId": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ad13dc98-c69f-4d97-801d-2076f77897f4",
      "name": "03b FN: Parse Status Command",
      "type": "n8n-nodes-base.code",
      "position": [
        192,
        -592
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import re\n\nout_items = []\n\nfor item in items:\n    text = item[\"json\"].get(\"message\", {}).get(\"text\", \"\").strip()\n    parts = text.split(maxsplit=1)\n\n    if len(parts) == 2:\n        correlation_id = parts[1].strip()\n        # quick regex UUID check\n        if not re.match(r'^[0-9a-fA-F-]{36}$', correlation_id):\n            correlation_id = None\n    else:\n        correlation_id = None\n\n    out_items.append({\n        \"json\": {\n            \"correlation_id\": correlation_id,\n            \"chat_id\": item[\"json\"][\"message\"][\"chat\"][\"id\"]\n        }\n    })\n\nreturn out_items\n"
      },
      "typeVersion": 2
    },
    {
      "id": "0892a7ae-2f00-4f66-89f1-05ed68d941be",
      "name": "04b DB: Get Ticket Status",
      "type": "n8n-nodes-base.postgres",
      "notes": "Fetches ticket info by correlation ID. Returns subject, status, timestamps. Handles missing tickets through the downstream IF node.",
      "position": [
        976,
        -960
      ],
      "parameters": {
        "query": "SELECT subject, status, created_at, updated_at, chat_id\nFROM tickets\nWHERE correlation_id = $1::uuid;\n",
        "options": {
          "queryReplacement": "={{$json.correlation_id}}"
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "retryOnFail": true,
      "typeVersion": 2.6,
      "alwaysOutputData": true
    },
    {
      "id": "b2248f84-10dc-464c-a611-6e4b924932c9",
      "name": "05b Telegram: Status Reply",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2352,
        -512
      ],
      "parameters": {
        "text": "=\u2705 Ticket ID: {{ $json.chat_id }}\n\ud83d\udcc4 Ticket: {{ $json.subject }}\n\ud83d\udccc Status: {{ $json.status }}\n\ud83d\udd52 Created: {{ new Date($json.created_at).toLocaleString(\"en-GB\", { dateStyle: \"medium\", timeStyle: \"short\" }) }}\n\ud83d\udd04 Last Updated: {{ new Date($json.updated_at).toLocaleString(\"en-GB\", { dateStyle: \"medium\", timeStyle: \"short\" }) }}\n\n",
        "chatId": "={{ $('02 Switch: Route by Command').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "cf87371a-3909-434e-88b3-42f6a4b80194",
      "name": "03b1 IF: Has Correlation ID",
      "type": "n8n-nodes-base.if",
      "position": [
        656,
        -944
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3a901b12-fe84-4f01-993a-185a2753eb0e",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.correlation_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "cbae7eab-6cb1-46f6-a2ea-58f0a5115929",
      "name": "05b Telegram: Status Reply (Error)",
      "type": "n8n-nodes-base.telegram",
      "notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
      "position": [
        976,
        -688
      ],
      "parameters": {
        "text": "=\u274c Please provide a correlation ID.\nFormat: /status correlation_id\n",
        "chatId": "={{$json.chat_id}}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "997d1d5f-ad28-4a2f-90f6-bdcc4c3e02fb",
      "name": "Telegram: Invalid Command",
      "type": "n8n-nodes-base.telegram",
      "position": [
        192,
        736
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f I didn\u2019t understand that request.\nTry /new or /status <ID>.",
        "chatId": "={{ $json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "aef8342f-17b0-45f5-b8ae-823b50ab5ccf",
      "name": "03c FN: Parse Update Command",
      "type": "n8n-nodes-base.code",
      "position": [
        512,
        160
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import re\n\nout_items = []\n\nfor item in items:\n    text = item[\"json\"].get(\"message\", {}).get(\"text\", \"\").strip()\n    parts = text.split(maxsplit=2)\n\n    if len(parts) == 3:\n        correlation_id, new_status = parts[1], parts[2].lower()\n        if not re.match(r'^[0-9a-fA-F-]{36}$', correlation_id):\n            correlation_id = None\n    else:\n        correlation_id, new_status = None, None\n\n    out_items.append({\n        \"json\": {\n            \"correlation_id\": correlation_id,\n            \"new_status\": new_status,\n            \"chat_id\": item[\"json\"][\"message\"][\"chat\"][\"id\"]\n        }\n    })\n\nreturn out_items\n"
      },
      "typeVersion": 2
    },
    {
      "id": "def5eb31-46b0-4db1-92d0-40dedbb62e4e",
      "name": "03c1 IF: Has Correlation ID",
      "type": "n8n-nodes-base.if",
      "position": [
        1216,
        -64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "49a8e0db-73d3-4615-add4-c21fe8eb2fb4",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.correlation_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8167b85a-e6b9-4b6e-a26b-88f2760bd0f9",
      "name": "Send a text message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1552,
        224
      ],
      "parameters": {
        "text": "=\u274c Invalid or missing correlation ID. Format: /update <ID> <status>.",
        "chatId": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "9acad108-3f50-414c-8b64-a69fc3f6c344",
      "name": "03c2 IF: Valid Status",
      "type": "n8n-nodes-base.if",
      "position": [
        1568,
        -80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "9ee9632a-361a-4cd3-a842-8e839ae84c2d",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"new_status\"] }}",
              "rightValue": "new"
            },
            {
              "id": "5e821125-60f9-45ce-b803-f50a5a3b0776",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"new_status\"] }}",
              "rightValue": "in_progress"
            },
            {
              "id": "8205c0d2-293f-43bc-aaec-2200f801b851",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"new_status\"] }}",
              "rightValue": "resolved"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "25588539-1ec7-46c8-8835-51baa7b35ba9",
      "name": "05c Telegram: Invalid Status",
      "type": "n8n-nodes-base.telegram",
      "notes": "Sends user-facing messages back to Telegram. Content depends on workflow branch (acknowledgment, errors, updates).",
      "position": [
        2352,
        400
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f Invalid status. Allowed values: new, in_progress, resolved.",
        "chatId": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "681309cf-a699-435c-8896-1a00c35c3bc6",
      "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": [
        2304,
        128
      ],
      "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": "74e0d370-d999-43b6-8628-1fe48602c875",
      "name": "03c0 IF: Is Operator",
      "type": "n8n-nodes-base.if",
      "position": [
        816,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "02a8b086-3e20-4576-a746-9e0bde67aba4",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"chat_id\"] }}",
              "rightValue": "YOUR_OPERATOR_ID"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "6d4e5147-1b94-42b7-b727-9478c56496ab",
      "name": "05c0 Telegram: Unauthorized Update Attempt",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1232,
        352
      ],
      "parameters": {
        "text": "=\u274c You don\u2019t have permission to update tickets.",
        "chatId": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "680d87b3-88ff-48b8-833c-b5b322e86bf5",
      "name": "04c1 DB: Get Ticket Owner",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2816,
        128
      ],
      "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": "0d248692-2d2f-4f83-8372-62dc3f119400",
      "name": "04b1 IF: Ticket Belongs To User",
      "type": "n8n-nodes-base.if",
      "position": [
        1984,
        -496
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "19a37b2c-e9ae-4a6c-9e6d-47f3fa7e5e69",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"chat_id\"] }}",
              "rightValue": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.chat.id }}"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "c3ac8c89-8578-4415-90f6-ed2e8eed787a",
      "name": "05b1 Telegram: Unauthorized Status Check",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2368,
        -224
      ],
      "parameters": {
        "text": "=\u274c You do not have access to this ticket.\nOnly the ticket creator can view its status.",
        "chatId": "={{ $('02 Switch: Route by Command').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "9acff907-71f9-464b-b575-95238009bc69",
      "name": "04c1a IF: Resolved or In Progress",
      "type": "n8n-nodes-base.if",
      "position": [
        3168,
        32
      ],
      "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": "1e6afb7d-537a-4aea-8762-d2c75c42d2f0",
      "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": [
        3536,
        -80
      ],
      "parameters": {
        "text": "=\ud83c\udf89 Good news! Your ticket ({{ $json.correlation_id }}) has been resolved.  \nYou can check details anytime with:  \n/status {{ $json.correlation_id }}",
        "chatId": "={{ $json.chat_id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "99688c3d-8bd7-4b8c-9861-23fb3d322581",
      "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": [
        3536,
        160
      ],
      "parameters": {
        "text": "=\ud83d\udd04 Your ticket ({{ $json.correlation_id }}) is now being worked on.  \nWe\u2019ll notify you once it\u2019s resolved.",
        "chatId": "={{ $json.chat_id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "b54c2084-2bfd-40c0-b07c-8c7d9b35362f",
      "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": [
        3088,
        320
      ],
      "parameters": {
        "text": "=\u2705 <b>Ticket {{ $json.correlation_id }}</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": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.2
    },
    {
      "id": "f8c20998-f5c0-4223-afaa-4760712aa2d1",
      "name": "04b0 IF: DB Lookup Failed?",
      "type": "n8n-nodes-base.if",
      "position": [
        1728,
        -736
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f367a262-4b55-40ad-a0ef-711ac9ebfa10",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ !!$json.error }}",
              "rightValue": "true"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6fa0c0d8-1975-47c9-bb28-82bc528d8c1b",
      "name": "05b0 Telegram: Status DB Error",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2352,
        -752
      ],
      "parameters": {
        "text": "=\u274c Sorry, I couldn\u2019t fetch your ticket right now. Please try again in a minute.",
        "chatId": "={{ $('02 Switch: Route by Command').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "dda44929-b58d-42a8-9f89-307489323c97",
      "name": "05c0 IF: Operator Reply Failed?",
      "type": "n8n-nodes-base.if",
      "position": [
        3408,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4a912629-cc2e-43b0-9ee1-cda03feda4b0",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ !!$json.error }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2e6fde8d-6bb7-421c-8fbd-dc10d672be2b",
      "name": "Telegram: Admin Alert \u2014 Operator Reply Failed",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3712,
        304
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f Operator reply could not be delivered.  \nTicket: {{ $('04c DB: Update Ticket Status').item.json.correlation_id }}  \nStatus: {{ $('04c DB: Update Ticket Status').item.json.status }}  \nOperator: {{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "chatId": "={{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "068e4ac0-c802-4bb7-a0fa-4d81c4169936",
      "name": "Notify Failed?",
      "type": "n8n-nodes-base.if",
      "position": [
        4000,
        32
      ],
      "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": "73c0c8b5-2385-495e-b341-a0e95faae5f0",
      "name": "Execute a SQL query",
      "type": "n8n-nodes-base.postgres",
      "position": [
        4320,
        16
      ],
      "parameters": {
        "query": "INSERT INTO workflow_errors\n  (workflow_id, workflow_name, execution_id, last_node_executed, error_message, json_payload)\nVALUES\n  ($1, $2, $3, $4, $5, $6::jsonb);",
        "options": {
          "queryReplacement": "={{ $workflow.id }},{{ $workflow.name }},{{ $execution.id }},NotifyUser,{{ $json.error?.message || 'unknown' }},{{ JSON.stringify($json) }}"
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "0f0761c5-6a16-4fcc-94b3-9a8a37ff047b",
      "name": "04c2 DB: Insert Audit Row",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2560,
        128
      ],
      "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{{ $('01 Telegram Trigger: Intake + Status').item.json.message.from.id }}"
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "ff81de50-249c-49fe-a014-78e703b0e005",
      "name": "04b1 IF: No Ticket Found",
      "type": "n8n-nodes-base.if",
      "position": [
        1328,
        -960
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1a87141a-6e78-4222-9523-00795be95f6f",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json[\"subject\"] }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "657b78f7-82d6-4dfa-8514-63d99899d91c",
      "name": "Send a text message1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1712,
        -976
      ],
      "parameters": {
        "text": "=\u274c No ticket found with that ID.\nDouble-check your ID or create a new ticket with /new",
        "chatId": "={{ $('02 Switch: Route by Command').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "427c8ad1-e42f-4454-b54d-513df32d111f",
      "name": "03b IF: Has Valid Correlation ID Format",
      "type": "n8n-nodes-base.if",
      "position": [
        496,
        -592
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0bfef915-ea45-4b6d-bf12-8999b67b8044",
              "operator": {
                "type": "string",
                "operation": "regex"
              },
              "leftValue": "={{$json.correlation_id}}",
              "rightValue": "=^[0-9a-fA-F-]{36}$"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "77001b07-a1e4-4e9c-b015-e3626b10f43a",
      "name": "Send a text message2",
      "type": "n8n-nodes-base.telegram",
      "position": [
        880,
        -400
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f Invalid ticket ID format. Please provide a valid correlation ID (UUID).",
        "chatId": "={{$json.chat_id}}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1bc21cd7-0689-43d3-8cda-cb5a153526f4",
      "name": "Welcome Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        160,
        -992
      ],
      "parameters": {
        "text": "=\ud83d\udc4b <b>Welcome to the Support Bot</b>  \n\nYou can create and manage tickets right here:  \n\n\u2022 <b>/new</b> \u2014 Open a new support ticket  \n\u2022 <b>/update &lt;ID&gt; &lt;status&gt;</b> \u2014 Update your ticket\u2019s status  \n\u2022 <b>/status &lt;ID&gt;</b> \u2014 Check the current status of a ticket  \n\n\ud83d\udca1 Save your <b>Ticket ID</b> when you create one \u2014 you\u2019ll need it for updates. \u2705\n",
        "chatId": "={{ $json.message.from.id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c5a5954e-ec31-40f0-87fe-4ef507a081e3",
      "name": "Send a text message3",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1216,
        944
      ],
      "parameters": {
        "text": "=\u274c <b>You are not authorized to use this command.</b>",
        "chatId": "={{ $json.message.from.id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "4f391512-66b6-4239-a7ee-fba38a6ec273",
      "name": "Check Admin",
      "type": "n8n-nodes-base.if",
      "position": [
        704,
        544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ce4f2418-7a43-44b5-845e-8abf8d0108b2",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{$json[\"message\"][\"from\"][\"id\"]}}",
              "rightValue": "YOUR_ADMIN_ID"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "f80cf5ce-d6eb-4795-9dc2-577442c05f72",
      "name": "DB: List Tickets",
      "type": "n8n-nodes-base.postgres",
      "position": [
        1216,
        672
      ],
      "parameters": {
        "query": "SELECT correlation_id, subject, status, created_at\nFROM tickets\nORDER BY created_at DESC\nLIMIT 10;",
        "options": {},
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "4e2e1d2d-de49-4850-9a4a-e63ff069891e",
      "name": "Send a text message4",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1632,
        672
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "chatId": "={{ $json.chat_id }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "51eb9b7c-f7cb-4ce4-abb2-d482ccb0850b",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        1424,
        672
      ],
      "parameters": {
        "jsCode": "const tickets = items;\n\nlet message = \"\ud83d\udccb <b>Latest Tickets</b>\\n\\n\";\n\ntickets.forEach((row, i) => {\n  message += `${i+1}. <b>ID:</b> ${row.json.correlation_id}\\n`;\n  message += `   <b>Status:</b> ${row.json.status}\\n`;\n  message += `   <i>${row.json.subject || \"No subject\"}</i>\\n`;\n  message += `   Created: ${row.json.created_at}\\n\\n`;\n});\n\n// pull original chat_id from the trigger\nconst chatId = $(\"01 Telegram Trigger: Intake + Status\").item.json.message.from.id;\n\nreturn [{ json: { text: message, chat_id: chatId } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8baac22d-8d39-4516-85e0-610b1c03346e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1904,
        -368
      ],
      "parameters": {
        "color": 5,
        "width": 736,
        "height": 1104,
        "content": "# \ud83d\udee0 Setup Requirements\n\n---\n\n## 1\ufe0f\u20e3 Database Tables\n- **tickets**  \n  `(id, correlation_id, chat_id, requester_name, requester_email, requester_phone, subject, description, status, priority, dedupe_key, created_at, updated_at)`\n\n- **ticket_audit**  \n  `(ticket_id, correlation_id, action, new_status, actor_chat_id, created_at)`\n\n- **workflow_errors**  \n  `(workflow_id, workflow_name, execution_id, last_node_executed, error_message, json_payload, created_at)`\n\n---\n\n## 2\ufe0f\u20e3 Stored Function: `upsert_ticket`\n- Purpose: insert **or** update tickets.  \n- **Inputs:**  \n  `correlation_id, source, external_id, requester_name, requester_email, requester_phone, subject, description, status, priority, dedupe_key, external_id`  \n- **Returns:**  \n  `ticket_id, correlation_id, chat_id`\n\n---\n\n## 3\ufe0f\u20e3 Credentials\n- Add **Postgres** credentials in n8n (must match your DB).  \n- Add **Telegram Bot** credentials in n8n.  \n\n---\n\n## 4\ufe0f\u20e3 Placeholders to Replace\n- `YOUR_ADMIN_ID` \u2192 replace with your own Telegram ID (for admin-only commands like /list).  \n- `YOUR_OPERATOR_ID` \u2192 replace with the operator\u2019s Telegram ID (for /update permissions).   \n\n\ud83d\udc49 Use [@userinfobot](https://t.me/userinfobot) in Telegram to find your ID.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e72863ee-979a-46c4-90dd-98572aa027d3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1120,
        -368
      ],
      "parameters": {
        "width": 688,
        "height": 1104,
        "content": "# \ud83d\udccc Function: upsert_ticket\n\n### Purpose \u2192 Insert or update a support ticket in the tickets table.\n### Returns \u2192 id, correlation_id, chat_id.\n\n### \ud83e\udde9 SQL Template\n-- Create or replace the upsert_ticket function\nCREATE OR REPLACE FUNCTION upsert_ticket(\n    p_correlation_id UUID,\n    p_source TEXT,\n    p_external_id TEXT,\n    p_requester_name TEXT,\n    p_requester_email TEXT,\n    p_requester_phone TEXT,\n    p_subject TEXT,\n    p_description TEXT,\n    p_status TEXT,\n    p_priority TEXT,\n    p_dedupe_key TEXT,\n    p_chat_id TEXT\n)\nRETURNS TABLE (\n    id BIGINT,\n    correlation_id UUID,\n    chat_id TEXT\n) AS $$\nBEGIN\n    INSERT INTO tickets (\n        correlation_id, source, external_id,\n        requester_name, requester_email, requester_phone,\n        subject, description, status, priority, dedupe_key, chat_id,\n        created_at, updated_at\n    )\n    VALUES (\n        p_correlation_id, p_source, p_external_id,\n        p_requester_name, p_requester_email, p_requester_phone,\n        p_subject, p_description, p_status, p_priority, p_dedupe_key, p_chat_id,\n        NOW(), NOW()\n    )\n    ON CONFLICT (correlation_id)\n    DO UPDATE SET\n        requester_name = EXCLUDED.requester_name,\n        requester_email = EXCLUDED.requester_email,\n        requester_phone = EXCLUDED.requester_phone,\n        subject = EXCLUDED.subject,\n        description = EXCLUDED.description,\n        status = EXCLUDED.status,\n        priority = EXCLUDED.priority,\n        dedupe_key = EXCLUDED.dedupe_key,\n        updated_at = NOW()\n    RETURNING tickets.id, tickets.correlation_id, tickets.chat_id;\nEND;\n$$ LANGUAGE plpgsql;\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Check Admin": {
      "main": [
        [
          {
            "node": "DB: List Tickets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send a text message3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Failed?": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB: List Tickets": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Send a text message4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03c0 IF: Is Operator": {
      "main": [
        [
          {
            "node": "03c1 IF: Has Correlation ID",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "05c0 Telegram: Unauthorized Update Attempt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send a text message3": {
      "main": [
        []
      ]
    },
    "03c2 IF: Valid Status": {
      "main": [
        [
          {
            "node": "04c DB: Update Ticket Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "05c Telegram: Invalid Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04a DB: Upsert Ticket": {
      "main": [
        [
          {
            "node": "05a Telegram Ack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03a FN: Normalize + Hash": {
      "main": [
        [
          {
            "node": "04a DB: Upsert Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04b1 IF: No Ticket Found": {
      "main": [
        [
          {
            "node": "Send a text message1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "04b0 IF: DB Lookup Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04b DB: Get Ticket Status": {
      "main": [
        [
          {
            "node": "04b1 IF: No Ticket Found",
            "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
          }
        ]
      ]
    },
    "04b0 IF: DB Lookup Failed?": {
      "main": [
        [
          {
            "node": "05b0 Telegram: Status DB Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "04b1 IF: Ticket Belongs To User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "02 Switch: Route by Command": {
      "main": [
        [
          {
            "node": "Welcome Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "03b FN: Parse Status Command",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "03a FN: Normalize + Hash",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "03c FN: Parse Update Command",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check Admin",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Telegram: Invalid Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03b1 IF: Has Correlation ID": {
      "main": [
        [
          {
            "node": "04b DB: Get Ticket Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "05b Telegram: Status Reply (Error)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03c1 IF: Has Correlation ID": {
      "main": [
        [
          {
            "node": "03c2 IF: Valid Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send a text message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03b FN: Parse Status Command": {
      "main": [
        [
          {
            "node": "03b IF: Has Valid Correlation ID Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03c FN: Parse Update Command": {
      "main": [
        [
          {
            "node": "03c0 IF: Is Operator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04c DB: Update Ticket Status": {
      "main": [
        [
          {
            "node": "04c2 DB: Insert Audit Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04b1 IF: Ticket Belongs To User": {
      "main": [
        [
          {
            "node": "05b Telegram: Status Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "05b1 Telegram: Unauthorized Status Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "05c0 IF: Operator Reply Failed?": {
      "main": [
        [
          {
            "node": "Telegram: Admin Alert \u2014 Operator Reply Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "05c1a Telegram: Notify Resolved": {
      "main": [
        [
          {
            "node": "Notify Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "04c1a IF: Resolved or In Progress": {
      "main": [
        [
          {
            "node": "05c1a Telegram: Notify Resolved",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "05c1b Telegram: Notify In Progress",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "05c Telegram: Update Confirmation": {
      "main": [
        [
          {
            "node": "05c0 IF: Operator Reply Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "05c1b Telegram: Notify In Progress": {
      "main": [
        [
          {
            "node": "Notify Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "01 Telegram Trigger: Intake + Status": {
      "main": [
        [
          {
            "node": "02 Switch: Route by Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "03b IF: Has Valid Correlation ID Format": {
      "main": [
        [
          {
            "node": "03b1 IF: Has Correlation ID",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send a text message2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}