{
  "name": "Nodbot - Yandex Cloud Functions to n8n secure webhook",
  "nodes": [
    {
      "parameters": {
        "path": "yandex-cloud-functions-to-n8n",
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "id": "ccb6345a-fca0-4075-b597-241df9c8bc67",
      "name": "n8n Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const crypto = require('crypto');\nconst secret = $env.YC_N8N_WEBHOOK_SECRET;\nif (!secret) throw new Error('YC_N8N_WEBHOOK_SECRET is not configured');\n\nconst headers = $json.headers ?? {};\nconst body = $json.body ?? $json;\nconst signature = String(headers['x-nodbot-signature'] ?? headers['X-Nodbot-Signature'] ?? '');\nconst timestamp = String(headers['x-nodbot-timestamp'] ?? headers['X-Nodbot-Timestamp'] ?? '');\nconst eventId = String(body.event_id ?? '').trim();\n\nif (!eventId) throw new Error('Missing event_id');\nif (!timestamp || Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) {\n  throw new Error('Webhook timestamp is missing or too old');\n}\n\nconst raw = JSON.stringify(body);\nconst expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${raw}`).digest('hex');\nif (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {\n  throw new Error('Invalid Cloud Functions signature');\n}\n\nreturn [{\n  json: {\n    event_id: eventId,\n    idempotency_key: `yc-functions:${eventId}`,\n    event_type: body.event_type,\n    payload: body,\n    verified_at: new Date().toISOString()\n  }\n}];"
      },
      "id": "8afa45ec-4862-402e-a00d-c6d54bd61c41",
      "name": "Verify HMAC signature",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        260
      ]
    },
    {
      "parameters": {},
      "id": "8461577a-4dd6-41dc-908c-49f3b37fd70d",
      "name": "Check idempotency",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const crypto = require('crypto');\nconst secret = $env.YC_N8N_WEBHOOK_SECRET;\nif (!secret) throw new Error('YC_N8N_WEBHOOK_SECRET is not configured');\n\nconst headers = $json.headers ?? {};\nconst body = $json.body ?? $json;\nconst signature = String(headers['x-nodbot-signature'] ?? headers['X-Nodbot-Signature'] ?? '');\nconst timestamp = String(headers['x-nodbot-timestamp'] ?? headers['X-Nodbot-Timestamp'] ?? '');\nconst eventId = String(body.event_id ?? '').trim();\n\nif (!eventId) throw new Error('Missing event_id');\nif (!timestamp || Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) {\n  throw new Error('Webhook timestamp is missing or too old');\n}\n\nconst raw = JSON.stringify(body);\nconst expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${raw}`).digest('hex');\nif (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {\n  throw new Error('Invalid Cloud Functions signature');\n}\n\nreturn [{\n  json: {\n    event_id: eventId,\n    idempotency_key: `yc-functions:${eventId}`,\n    event_type: body.event_type,\n    payload: body,\n    verified_at: new Date().toISOString()\n  }\n}];"
      },
      "id": "835b9cef-c494-47c0-ac3f-3c42091aa96e",
      "name": "Route by event type",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        840,
        260
      ]
    },
    {
      "parameters": {},
      "id": "e3352642-57af-4416-bb06-c54193e1c40b",
      "name": "Call business workflow",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        1120,
        260
      ]
    },
    {
      "parameters": {},
      "id": "1aefd862-f07a-487a-8d5f-ff14b5aa025c",
      "name": "Respond to Cloud Function",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 2,
      "position": [
        1400,
        260
      ]
    }
  ],
  "connections": {
    "n8n Webhook": {
      "main": [
        [
          {
            "node": "Verify HMAC signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify HMAC signature": {
      "main": [
        [
          {
            "node": "Check idempotency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check idempotency": {
      "main": [
        [
          {
            "node": "Route by event type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by event type": {
      "main": [
        [
          {
            "node": "Call business workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call business workflow": {
      "main": [
        [
          {
            "node": "Respond to Cloud Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    "nodbot",
    "production",
    "template"
  ],
  "triggerCount": 1,
  "updatedAt": "2026-05-30T00:00:00.000Z",
  "versionId": "d8f94409-0828-4ed7-8519-af558da65ea6",
  "meta": {
    "templateCredsSetupCompleted": false
  }
}