{
  "name": "Uptime Monitor - Multi Service (v3)",
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        16,
        368
      ],
      "id": "b3052d77-41b3-4966-8c76-6991ded70923",
      "name": "No Change"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "monitor-alert",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -880,
        336
      ],
      "id": "3ce1ac31-23ea-4504-acc8-156cdd9187d6",
      "name": "Webhook"
    },
    {
      "parameters": {
        "fileSelector": "/home/node/.n8n-files/monitor_states.json",
        "options": {}
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        -672,
        336
      ],
      "id": "1fc4b9af-23c0-49c1-8caf-bdda6442be42",
      "name": "Read States JSON",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// 1. OBTENER DATOS DEL WEBHOOK\nconst webhookData = $('Webhook').first().json.body;\n\n// Usar service si existe, sino usar site como nombre\nconst serviceName = webhookData.service || webhookData.site || 'Servicio Desconocido';\nconst newStatus = String(webhookData.error_code).trim();\nconst site = webhookData.site;\nconst timestamp = webhookData.timestamp || new Date().toISOString();\n\n// 2. LEER ESTADOS ANTERIORES DEL JSON\nlet allStates = {};\nlet oldStatus = 'Primer chequeo';\n\nconst binaryData = $input.first().binary;\nif (binaryData && binaryData.data) {\n  try {\n    const buffer = await this.helpers.getBinaryDataBuffer(0, 'data');\n    const jsonContent = buffer.toString('utf8').trim();\n    if (jsonContent && jsonContent !== '{}') {\n      allStates = JSON.parse(jsonContent);\n    }\n    if (allStates[serviceName]) {\n      oldStatus = allStates[serviceName].current || 'Primer chequeo';\n    }\n  } catch (error) {\n    console.log('Error leyendo JSON:', error);\n  }\n}\n\n// 3. DETECTAR SI HAY CAMBIO\nconst hasChanged = (newStatus !== oldStatus);\nconst isUp = (newStatus === '200' || newStatus === '302');\n\n// 4. ACTUALIZAR ESTADO DEL SERVICIO\nif (!allStates[serviceName]) {\n  allStates[serviceName] = {\n    current: newStatus,\n    previous: null,\n    last_change: timestamp,\n    history: []\n  };\n} else {\n  if (hasChanged) {\n    allStates[serviceName].history.push({\n      from: oldStatus,\n      to: newStatus,\n      timestamp: timestamp\n    });\n    if (allStates[serviceName].history.length > 50) {\n      allStates[serviceName].history.shift();\n    }\n    allStates[serviceName].last_change = timestamp;\n  }\n  allStates[serviceName].previous = oldStatus;\n  allStates[serviceName].current = newStatus;\n}\n\nlet displayStatus = newStatus;\nif (newStatus === '000') displayStatus = '000 (Sin Conexi\u00f3n)';\n\nreturn {\n  json: {\n    alert: hasChanged,\n    service: serviceName,\n    site: site,\n    new_status: displayStatus,\n    old_status: oldStatus,\n    type: isUp ? 'recovered' : 'down',\n    timestamp: timestamp,\n    all_states: allStates,\n    json_to_save: JSON.stringify(allStates, null, 2)\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -448,
        336
      ],
      "id": "d2bd5243-13c7-475c-9db2-4e363fdd4069",
      "name": "Process Status Change"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "9350a1ce-3382-4a58-b138-ef25d26a51a3",
              "leftValue": "={{ $json.alert }}",
              "rightValue": "true",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -224,
        336
      ],
      "id": "10f52d6d-9834-4eb6-8a68-120c5841d22a",
      "name": "If Status Changed"
    },
    {
      "parameters": {
        "chatId": "794033826",
        "text": "={{ $json.type == 'recovered' ? '\ud83d\udfe2 \u00a1SERVICIO RECUPERADO!' : '\ud83d\udea8 \u00a1ALERTA: SITIO CA\u00cdDO!' }}\n\n\ud83d\udd27 **Servicio:** {{ $json.service }}\n\ud83c\udf10 **URL:** {{ $json.site }}\n\ud83d\udcca **Estado Actual:** {{ $json.new_status }}\n\ud83d\udccb **Estado Anterior:** {{ $json.old_status }}\n\ud83d\udcc5 **Hora:** {{ $json.timestamp }}",
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        16,
        176
      ],
      "id": "1de1e8dd-497c-4ae6-b3c6-226237a690f3",
      "name": "Send Alert to Telegram",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "toText",
        "sourceProperty": "data",
        "options": {
          "fileName": "monitor_states.json"
        }
      },
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        -272,
        544
      ],
      "id": "5ea55742-d4b3-46a2-98bd-7d2b0d4bef85",
      "name": "Convert States to JSON File"
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "/home/node/.n8n-files/monitor_states.json",
        "options": {
          "append": false
        }
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        -80,
        544
      ],
      "id": "d9464f1f-97c0-467c-a91f-10be5b6c14e6",
      "name": "Save States JSON",
      "executeOnce": false,
      "retryOnFail": false,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "json-states",
              "name": "=data",
              "value": "={{ JSON.stringify($json.all_states, null, 2) }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -448,
        544
      ],
      "id": "55134575-6462-4a5c-b41d-106e9f7c422c",
      "name": "Prepare JSON for Save"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Read States JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read States JSON": {
      "main": [
        [
          {
            "node": "Process Status Change",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Status Change": {
      "main": [
        [
          {
            "node": "If Status Changed",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare JSON for Save",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Status Changed": {
      "main": [
        [
          {
            "node": "Send Alert to Telegram",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Change",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare JSON for Save": {
      "main": [
        [
          {
            "node": "Convert States to JSON File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert States to JSON File": {
      "main": [
        [
          {
            "node": "Save States JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": false,
    "timeSavedMode": "fixed",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "ff1dd1b3-aec1-492a-b0cd-90daec70e706",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "AjBDxecKidHHOm2c6NYg9",
  "tags": []
}