{
  "id": "",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Hackathon Participant Badge + QR Check-in (HTML \u2192 PDF \u2192 Gmail)",
  "tags": [],
  "nodes": [
    {
      "id": "97a3afd6-32bf-412d-9e20-91f5fee5a553",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -448,
        304
      ],
      "parameters": {
        "path": "hackathon-badge",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "072fe3df-815f-4eda-ad16-1624c76ff355",
      "name": "Validate Input",
      "type": "n8n-nodes-base.function",
      "position": [
        -272,
        304
      ],
      "parameters": {
        "functionCode": "// Extract only the actual payload from the webhook\nconst payload = $input.first().json.body;\n\n// Required fields\nconst required = [\"name\", \"email\", \"event\"];\nconst errors = [];\n\n// Check required fields\nrequired.forEach(field => {\n  if (!payload[field] || String(payload[field]).trim() === \"\") {\n    errors.push(`${field} is required`);\n  }\n});\n\n// Very basic email format check\nif (!payload.email || !payload.email.includes(\"@\") || !payload.email.includes(\".\")) {\n  errors.push(\"Invalid email format\");\n}\n\nif (errors.length > 0) {\n  throw new Error(\"VALIDATION_ERROR: \" + errors.join(\" | \"));\n}\n\n// Pass only the clean data forward\nreturn [{ json: payload }];"
      },
      "typeVersion": 1
    },
    {
      "id": "d95fcf37-9a52-4446-ad80-9c4a1a2f7111",
      "name": "Email Valid?",
      "type": "n8n-nodes-base.if",
      "position": [
        64,
        304
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.valid }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "74a8b677-e908-489b-939e-24c0b3a3d55f",
      "name": "Generate Badge ID & URL",
      "type": "n8n-nodes-base.function",
      "position": [
        432,
        288
      ],
      "parameters": {
        "functionCode": "const now = new Date();\nconst badgeId = `HACK-${now.getFullYear()}-${Math.floor(Date.now()/1000)}-${Math.random().toString(36).substr(2,6).toUpperCase()}`;\nconst verifyUrl = `https://yourdomain.com/verify-badge?id=${badgeId}`;\nconst issuedAt = now.toLocaleDateString('en-US', {\n  month: 'long',\n  day: 'numeric',\n  year: 'numeric'\n});\n\n// Direct QR code URL (no external node needed!)\nconst qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=300x300&format=png&data=${encodeURIComponent(verifyUrl)}`;\n\nreturn [{\n  json: {\n    ...$json,\n    badgeId,\n    verifyUrl,\n    issuedAt,\n    qrCodeUrl\n  }\n}];"
      },
      "typeVersion": 1
    },
    {
      "id": "c0b3e254-c96e-41ff-ba17-009ef42095eb",
      "name": "Download PDF",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        928,
        288
      ],
      "parameters": {
        "url": "={{ $json.pdf_url }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "01483244-ac10-409b-89b7-a4fe552c939e",
      "name": "Send Badge via Gmail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1120,
        288
      ],
      "parameters": {
        "sendTo": "={{ $('Validate Input').item.json.email }}",
        "message": "=<p style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; color: #1f2937;\">\n  Hi <strong>{{ $('Validate Input').item.json.name.split(\" \")[0] }}</strong>,\n</p>\n\n<p style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; color: #1f2937; line-height: 1.6;\">\n  Congratulations! Here is your <strong>official participant badge</strong> for:\n</p>\n\n<h2 style=\"text-align: center; color: #3b82f6; font-size: 28px; margin: 24px 0;\">\n  {{ $('Validate Input').item.json.event}}\n</h2>\n\n<table style=\"width: 100%; max-width: 600px; margin: 30px auto; background: #f8fafc; border-radius: 12px; padding: 20px; border: 1px solid #e2e8f0;\">\n  <tr>\n    <td style=\"padding: 8px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 15px;\">\n      <strong>Badge ID:</strong>\n    </td>\n    <td style=\"font-family: monospace; background: #e2e8f0; padding: 6px 12px; border-radius: 8px; font-weight: bold;\">\n      {{ $('Generate Badge ID & URL').item.json.badgeId }}\n    </td>\n  </tr>\n  <tr>\n    <td style=\"padding: 8px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 15px;\">\n      <strong>Verify Online:</strong>\n    </td>\n    <td>\n      <a href=\"{{ $('Generate Badge ID & URL').item.json.verifyUrl }}\" style=\"color: #3b82f6; text-decoration: none; font-weight: bold;\">Click here to verify</a>\n    </td>\n  </tr>\n</table>\n\n<p style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; color: #1f2937; line-height: 1.6; text-align: center;\">\n  <strong>Print the attached PDF</strong> or show it on your phone at check-in.<br>\n  The QR code links directly to your verification page.\n</p>\n\n<hr style=\"border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;\">\n\n<p style=\"text-align: center; color: #64748b; font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">\n  See you at the hackathon!<br>\n  <strong>The {{ $('Validate Input').item.json.event }} Team</strong>\n</p>",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "=Your Official {{ $('Validate Input').item.json.event }} Badge"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "bdf8ffc3-04ba-4043-a27c-77114808573c",
      "name": "Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1456,
        288
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "c996c87f-9fb4-4321-b268-b5d1de4bee92",
      "name": "Verifi Email",
      "type": "n8n-nodes-verifiemail.verifiEmail",
      "position": [
        -96,
        304
      ],
      "parameters": {
        "email": "={{ $json.email }}"
      },
      "credentials": {
        "verifiEmailApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4a3dfcce-07f8-4302-a6f8-9d77d989c004",
      "name": "HTML to PDF",
      "type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
      "position": [
        656,
        288
      ],
      "parameters": {
        "html_content": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>{{ $('Webhook Trigger').item.json.body.event }} - Badge</title>\n  <style>\n    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');\n    body { \n      margin: 0; \n      padding: 40px; \n      background: #0f172a; \n      font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif; \n    }\n    .badge { \n      width: 1056px; \n      height: 816px; \n      margin: auto; \n      background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n      border-radius: 32px; \n      padding: 60px; \n      box-shadow: 0 30px 60px rgba(0,0,0,0.7); \n      position: relative; \n      color: white; \n      overflow: hidden;\n    }\n    .header { \n      font-size: 56px; \n      font-weight: 900; \n      text-align: center; \n      color: #60a5fa; \n      margin-bottom: 20px; \n      text-shadow: 0 4px 10px rgba(0,0,0,0.5);\n    }\n    .name { \n      font-size: 88px; \n      font-weight: 900; \n      text-align: center; \n      margin: 40px 0; \n      color: #e0f2fe; \n      letter-spacing: 2px;\n      text-shadow: 0 6px 15px rgba(0,0,0,0.6);\n    }\n    .details { \n      font-size: 36px; \n      line-height: 1.8; \n      margin: 40px 0; \n      text-align: center;\n    }\n    .qr { \n      position: absolute; \n      bottom: 80px; \n      right: 80px; \n      background: white; \n      padding: 16px; \n      border-radius: 16px; \n      box-shadow: 0 10px 30px rgba(0,0,0,0.4);\n    }\n    .logo { \n      position: absolute; \n      top: 60px; \n      left: 60px; \n      width: 220px; \n      border-radius: 12px;\n    }\n    .badge-id { \n      position: absolute; \n      bottom: 80px; \n      left: 80px; \n      font-size: 28px; \n      font-weight: bold; \n      opacity: 0.9; \n      background: rgba(255,255,255,0.1); \n      padding: 8px 16px; \n      border-radius: 8px;\n    }\n    .footer { \n      position: absolute; \n      bottom: 40px; \n      left: 0; \n      right: 0; \n      text-align: center; \n      font-size: 20px; \n      opacity: 0.7;\n    }\n  </style>\n</head>\n<body>\n  <div class=\"badge\">\n    <img src=\"https://yourdomain.com/logo-white.png\" class=\"logo\" alt=\"Event Logo\">\n    <div class=\"header\">{{ $('Webhook Trigger').item.json.body.event.toUpperCase()}}</div>\n    <div class=\"name\">{{ $('Webhook Trigger').item.json.body.name.toUpperCase()}}</div>\n    <div class=\"details\">\n      Team: <strong>{{ $('Webhook Trigger').item.json.body.team || 'Individual'}}</strong><br>\n      Role: <strong>{{ $('Webhook Trigger').item.json.body.role|| 'Participant'}}</strong><br><br>\n      Issued: <strong>{{ $json.issuedAt }}</strong>\n    </div>\n    <div class=\"badge-id\">Badge ID: {{ $json.badgeId }}</div>\n    <div class=\"qr\">\n      <img src=\"{{ $json.qrCodeUrl }}\" width=\"220\" height=\"220\" alt=\"QR Code\">\n    </div>\n    <div class=\"footer\">Scan to verify \u2022 Show at check-in</div>\n  </div>\n</body>\n</html>"
      },
      "credentials": {
        "htmlcsstopdfApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "416e76d5-1ff1-4d86-b937-dfcb69e3b9fa",
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1296,
        288
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $('Validate Input').item.json.name }}",
            "Role": "={{ $('Validate Input').item.json.role }}",
            "Team": "={{ $('Validate Input').item.json.team }}",
            "Email": "={{ $('Validate Input').item.json.email }}",
            "Event": "={{ $('Validate Input').item.json.event }}",
            "Status": "Sent",
            "PDF URL": "={{ $('HTML to PDF').item.json.pdf_url }}",
            "Badge ID": "={{ $('Generate Badge ID & URL').item.json.badgeId }}",
            "Timestamp": "={{ $now }}",
            "Verify URL": "={{ $('Generate Badge ID & URL').item.json.verifyUrl }}",
            "Issued Date": "={{ $('Generate Badge ID & URL').item.json.issuedAt }}"
          },
          "schema": [
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Team",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Team",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Role",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Role",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Event",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Event",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Badge ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Badge ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Verify URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Verify URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Issued Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Issued Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "PDF URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "PDF URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_DOCUMENT_ID/edit#gid=0",
          "cachedResultName": "YOUR_SHEET_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DOCUMENT_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_DOCUMENT_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_DOCUMENT_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2b2adffb-dac3-4cf1-9b3c-a5936a162f25",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        336
      ],
      "parameters": {
        "height": 192,
        "content": "### **CREDENTIALS REQUIRED**\n\n* VerifiEmail at verifi.email\n* HTML \u2192 PDF at https://pdfmunk.com\n* Gmail \n* Google Sheets\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f18dafc5-23eb-454d-9ff3-8e5086f086ae",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        -112
      ],
      "parameters": {
        "width": 384,
        "height": 432,
        "content": "# Hackathon Badge Workflow\n\n### **HACKATHON BADGE WORKFLOW \u2013 FULLY AUTOMATED**\n\n**Webhook \u2192 Validate \u2192 Email Check \u2192 Generate ID + QR \u2192 HTML \u2192 PDF \u2192 Gmail + Sheets \u2192 Done**\n\n**What it does:**\n\n* Receives registration via POST\n* Blocks fake/disposable emails\n* Instantly creates PDF badge with QR\n* Emails inline preview + PDF attachment\n* Logs all details to Google Sheets\n"
      },
      "typeVersion": 1
    },
    {
      "id": "50b61d60-8bde-4a51-9394-ba98594c863c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -176
      ],
      "parameters": {
        "color": 5,
        "width": 672,
        "height": 640,
        "content": "# Validation Group \u2014 Validation & Safety\n\n## **VALIDATION & SAFETY (Blocks junk early)**\n\n**1. Validate Input**\n\n* Checks required fields: name, email, event\n* Rejects incomplete or invalid formats\n\n**2. VerifiEmail Node**\n\n* Real-time deliverability + disposable check\n* Only valid emails continue\n\n**3. Email Valid? (IF Node)**\n\n* **True:** continue\n* **False:** optional rejection path\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e123be75-b60d-4b1d-9596-19231ac79923",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -64
      ],
      "parameters": {
        "color": 5,
        "width": 432,
        "height": 496,
        "content": "#  Badge Creation Group \u2014 *Badge Creation*\n\n## BADGE CREATION \n\n**1. Generate Badge ID & URL**\n* Creates unique ID + verifyUrl\n* Generates QR code link\n* Sets formatted issue date\n\n**2. HTML to PDF**\n* Returns ready PDF URL\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c8115329-27bd-443b-b175-43b1945af610",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -112
      ],
      "parameters": {
        "color": 5,
        "width": 768,
        "height": 576,
        "content": "# Delivery & Logging Group\n\n## DELIVERY & LOGGING\n\n**1. Download PDF**\n* Fetches final badge PDF\n\n**2. Send Badge via Gmail**\n* Inline badge preview + PDF attachment\n* Polished HTML email\n\n**3. Log to Sheets**\n* One row: Name, Email, Team, Badge ID, Verify URL, PDF link\n\n**4. Success Response**\n* JSON confirmation returned to caller\n\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "",
  "connections": {
    "HTML to PDF": {
      "main": [
        [
          {
            "node": "Download PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download PDF": {
      "main": [
        [
          {
            "node": "Send Badge via Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Valid?": {
      "main": [
        [
          {
            "node": "Generate Badge ID & URL",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Verifi Email": {
      "main": [
        [
          {
            "node": "Email Valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Sheets": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input": {
      "main": [
        [
          {
            "node": "Verifi Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Validate Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Badge via Gmail": {
      "main": [
        [
          {
            "node": "Log to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Badge ID & URL": {
      "main": [
        [
          {
            "node": "HTML to PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}