{
  "name": "KyndredAI · MercadoPago → Google Sheets + aviso",
  "nodes": [
    {
      "parameters": {
        "content": "# 🔷 KyndredAI · MercadoPago → Google Sheets + aviso\n\nCuando entra un pago en MercadoPago, **verifica la firma**, trae los datos del pago y los **guarda en una planilla** + dispara un aviso.\n\n**Cómo funciona:** Webhook recibe la notificación → valida la firma `x-signature` (HMAC) → trae el pago de la API de MP → normaliza → Google Sheets → aviso.\n\n**Necesitás:** tu **Secret** de webhooks de MP (paso ②) + un **Access Token** de MP (credencial Header Auth) + una credencial de Google Sheets.\n\n⚠️ **Probá con datos de prueba antes de producción** — la verificación de firma es sensible al proveedor. Validá la firma con un webhook real de MP antes de confiar en ella.\n\nself-hosted o cloud · kyndredai.com",
        "height": 380,
        "width": 880,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [0, 0],
      "id": "f1f1f1f1-1111-4111-8111-ffffffffffff",
      "name": "README"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "mercadopago",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [40, 480],
      "id": "f2f2f2f2-2222-4222-8222-ffffffffffff",
      "name": "Recibir notificación MP (Webhook)",
      "webhookId": "f2b2c2d2-2222-4222-8222-ffffffffffff"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const crypto = require('crypto');\n\n// ⚠️ PEGÁ acá tu Secret de MercadoPago\n// (Tus integraciones → Webhooks → Configurar notificaciones → Clave secreta)\nconst SECRET = 'PEGA_TU_SECRET_DE_MERCADOPAGO_ACA';\n\nconst item = $input.first();\nconst headers = item.json.headers || {};\nconst body = item.json.body || {};\nconst query = item.json.query || {};\n\n// x-signature llega como \"ts=...,v1=...\"\nconst xSignature = headers['x-signature'] || '';\nconst xRequestId = headers['x-request-id'] || '';\nconst parts = {};\nxSignature.split(',').forEach(p => {\n  const [k, v] = p.split('=');\n  if (k && v) parts[k.trim()] = v.trim();\n});\nconst ts = parts.ts || '';\nconst v1 = parts.v1 || '';\n\n// data.id puede venir en la query (?data.id=) o en el body\nlet dataId = query['data.id'] || (body.data && body.data.id) || '';\ndataId = String(dataId);\n\n// Manifest EXACTO que pide MercadoPago:\nconst manifest = `id:${dataId};request-id:${xRequestId};ts:${ts};`;\nconst hash = crypto.createHmac('sha256', SECRET).update(manifest).digest('hex');\nconst signatureValid = Boolean(v1) && hash === v1;\n\nreturn [{ json: { paymentId: dataId, signatureValid } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [320, 480],
      "id": "f3f3f3f3-3333-4333-8333-ffffffffffff",
      "name": "Verificar firma (x-signature)"
    },
    {
      "parameters": {
        "conditions": {
          "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "loose", "version": 2 },
          "conditions": [
            { "id": "d0000001-0000-4000-8000-000000000001", "leftValue": "={{ $json.signatureValid }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [600, 480],
      "id": "f4f4f4f4-4444-4444-8444-ffffffffffff",
      "name": "¿Firma válida?"
    },
    {
      "parameters": {
        "url": "=https://api.mercadopago.com/v1/payments/{{ $json.paymentId }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [880, 380],
      "id": "f5f5f5f5-5555-4555-8555-ffffffffffff",
      "name": "Traer pago de MP",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "id": "e0000001-0000-4000-8000-000000000001", "name": "pago_id", "value": "={{ $json.id }}", "type": "string" },
            { "id": "e0000002-0000-4000-8000-000000000002", "name": "estado", "value": "={{ $json.status }}", "type": "string" },
            { "id": "e0000003-0000-4000-8000-000000000003", "name": "monto", "value": "={{ $json.transaction_amount }}", "type": "number" },
            { "id": "e0000004-0000-4000-8000-000000000004", "name": "email", "value": "={{ $json.payer.email }}", "type": "string" },
            { "id": "e0000005-0000-4000-8000-000000000005", "name": "descripcion", "value": "={{ $json.description }}", "type": "string" },
            { "id": "e0000006-0000-4000-8000-000000000006", "name": "fecha", "value": "={{ $json.date_approved }}", "type": "string" }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [1140, 380],
      "id": "f6f6f6f6-6666-4666-8666-ffffffffffff",
      "name": "Normalizar pago"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": { "__rl": true, "value": "", "mode": "list", "cachedResultName": "" },
        "sheetName": { "__rl": true, "value": "", "mode": "list", "cachedResultName": "" },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [],
          "schema": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [1400, 380],
      "id": "f7f7f7f7-7777-4777-8777-ffffffffffff",
      "name": "Guardar en Sheets",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [1660, 380],
      "id": "f8f8f8f8-8888-4888-8888-ffffffffffff",
      "name": "→ Notificar (WhatsApp/Email)"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [600, 700],
      "id": "f9f9f9f9-9999-4999-8999-ffffffffffff",
      "name": "Firma inválida (descartar)"
    },
    {
      "parameters": {
        "content": "## ① Configurá el webhook en MP\n\nEn MercadoPago → **Tus integraciones → Webhooks**, pegá la URL **production** de este nodo y suscribite al evento **payment**.\n\nMP manda solo el `data.id` — por eso después traemos el pago completo de la API.",
        "height": 300,
        "width": 260,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [0, 940],
      "id": "e1e1e1e1-1111-4111-8111-eeeeeeeeeeee",
      "name": "Setup 1"
    },
    {
      "parameters": {
        "content": "## ② Secret + Access Token\n\n**a) Secret (firma):** abrí **Verificar firma** y pegá tu *Clave secreta* de MP en la línea `SECRET = '...'`.\n\n**b) Access Token (API):** en **Traer pago de MP** → Credential → *Header Auth* → Name: `Authorization`, Value: `Bearer TU_ACCESS_TOKEN`.\n\n⚠️ Self-hosted: si Code falla con `crypto`, seteá la env `NODE_FUNCTION_ALLOW_BUILTIN=crypto`.",
        "height": 340,
        "width": 320,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [300, 940],
      "id": "e2e2e2e2-2222-4222-8222-eeeeeeeeeeee",
      "name": "Setup 2"
    },
    {
      "parameters": {
        "content": "### 🔁 Idempotencia (recomendado)\n\nMP puede mandar el **mismo** pago más de una vez. Para no duplicar filas, agregá un nodo **Remove Duplicates** (modo *Remove items processed in previous executions*) por `paymentId`, después de validar la firma.\n\nLo dejamos documentado para no embeber dependencias.",
        "height": 300,
        "width": 280,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [660, 940],
      "id": "e3e3e3e3-3333-4333-8333-eeeeeeeeeeee",
      "name": "Nota idempotencia"
    },
    {
      "parameters": {
        "content": "## ③ Conectá Google Sheets\n\n1. **Guardar en Sheets** → Credential → conectá tu Google.\n2. Elegí planilla + pestaña, mapeo **Map Automatically**.\n\nEncabezados sugeridos:\n**pago_id · estado · monto · email · descripcion · fecha**",
        "height": 280,
        "width": 300,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [1300, 940],
      "id": "e4e4e4e4-4444-4444-8444-eeeeeeeeeeee",
      "name": "Setup 3"
    }
  ],
  "connections": {
    "Recibir notificación MP (Webhook)": {
      "main": [[{ "node": "Verificar firma (x-signature)", "type": "main", "index": 0 }]]
    },
    "Verificar firma (x-signature)": {
      "main": [[{ "node": "¿Firma válida?", "type": "main", "index": 0 }]]
    },
    "¿Firma válida?": {
      "main": [
        [{ "node": "Traer pago de MP", "type": "main", "index": 0 }],
        [{ "node": "Firma inválida (descartar)", "type": "main", "index": 0 }]
      ]
    },
    "Traer pago de MP": {
      "main": [[{ "node": "Normalizar pago", "type": "main", "index": 0 }]]
    },
    "Normalizar pago": {
      "main": [[{ "node": "Guardar en Sheets", "type": "main", "index": 0 }]]
    },
    "Guardar en Sheets": {
      "main": [[{ "node": "→ Notificar (WhatsApp/Email)", "type": "main", "index": 0 }]]
    }
  },
  "active": false,
  "settings": { "executionOrder": "v1" },
  "pinData": {},
  "tags": []
}
