{
  "id": "uttaPostSample01",
  "name": "UttaPost sample: webhook receiver and scheduled draft",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "uttapost-events",
        "options": {
          "rawBody": true
        }
      },
      "id": "a1000000-0000-4000-8000-000000000001",
      "name": "UttaPost Webhook (post.published)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "webhookId": "a1000000-0000-4000-8000-0000000000a1"
    },
    {
      "parameters": {
        "jsCode": "// Verify the UttaPost signature (HMAC-SHA256 over \"t.rawBody\"). Needs NODE_FUNCTION_ALLOW_BUILTIN=crypto in n8n.\nconst crypto = require('crypto');\nconst secret = 'PASTE_WEBHOOK_SECRET_HERE'; // better: read it from an n8n credential or variable\nconst header = $input.first().json.headers['x-uttapost-signature'] || '';\nconst raw = await this.helpers.getBinaryDataBuffer(0, 'data'); // Webhook node option \"Raw Body\" must be on\nconst m = /^t=(\\d+),v1=([0-9a-f]{64})$/.exec(header);\nif (!m) throw new Error('missing or malformed X-UttaPost-Signature');\nif (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) throw new Error('timestamp too old');\nconst h = crypto.createHmac('sha256', secret);\nh.update(m[1] + '.');\nh.update(raw);\nconst expected = Buffer.from(h.digest('hex'));\nconst given = Buffer.from(m[2]);\nif (expected.length !== given.length || !crypto.timingSafeEqual(expected, given)) throw new Error('bad UttaPost signature');\nreturn $input.all();"
      },
      "id": "a1000000-0000-4000-8000-000000000002",
      "name": "Verify signature",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                6
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "id": "a1000000-0000-4000-8000-000000000003",
      "name": "Every Saturday 09:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://uttapost.ir/api/v1/drafts/generate",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"item_ids\": [12],\n  \"format\": \"post\"\n}",
        "options": {}
      },
      "id": "a1000000-0000-4000-8000-000000000004",
      "name": "Generate draft (preview, no charge)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        260,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_ME",
          "name": "UttaPost API key"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://uttapost.ir/api/v1/confirm",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"confirm_token\": \"{{ $json.data.confirm_token }}\"\n}",
        "options": {}
      },
      "id": "a1000000-0000-4000-8000-000000000005",
      "name": "Confirm (this is what spends)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        520,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_ME",
          "name": "UttaPost API key"
        }
      }
    }
  ],
  "connections": {
    "UttaPost Webhook (post.published)": {
      "main": [
        [
          {
            "node": "Verify signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Saturday 09:00": {
      "main": [
        [
          {
            "node": "Generate draft (preview, no charge)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate draft (preview, no charge)": {
      "main": [
        [
          {
            "node": "Confirm (this is what spends)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  }
}
