{
  "nodes": [
    {
      "id": "f2a4e703-2598-414b-8e2c-a43317171315",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        -128
      ],
      "parameters": {
        "width": 400,
        "height": 880,
        "content": "## Manage event participants and process QR code check-ins\n\n### Who is this for?\nEvent organizers, conference managers, and community teams who need automated participant management with registration and check-in tracking.\n\n### What this workflow does\n**Registration Flow:**\n- Receives registration via webhook\n- Generates unique ticket ID and QR code\n- Stores in Google Sheets and sends confirmation email\n\n**Check-in Flow:**\n- Decodes scanned QR code\n- Validates ticket and blocks duplicates\n- Sends Slack alerts for VIP arrivals\n- Returns attendance statistics\n\n### Setup\n1. Create Google Sheet with participant columns\n2. Connect Google Sheets and Gmail credentials\n3. Configure Slack for VIP notifications\n\n### Requirements\n- Google Sheets\n- Gmail account\n- Slack workspace"
      },
      "typeVersion": 1
    },
    {
      "id": "1228946c-c619-4a3d-afa3-5245cd52ea41",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 80,
        "content": "**Step 1: Registration**\nReceive participant data, create ticket ID, and save to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "f58e2b56-ebf4-4d98-957e-f2c387de94d9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 80,
        "content": "**Step 2: QR Code & Email**\nGenerate QR code with ticket data and send confirmation email with attachment."
      },
      "typeVersion": 1
    },
    {
      "id": "a2a90ffa-427f-4aae-b5bf-a367859b08fe",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 96,
        "content": "**Step 3: Check-in Validation**\nDecode QR, validate ticket, and check for duplicate entries."
      },
      "typeVersion": 1
    },
    {
      "id": "c4eb5603-e201-4939-a695-e23f4783db98",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        192
      ],
      "parameters": {
        "color": 7,
        "width": 260,
        "height": 80,
        "content": "**Step 4: VIP Handling**\nDetect VIP tickets and send Slack notification to event staff."
      },
      "typeVersion": 1
    },
    {
      "id": "7708123a-6137-4f8a-8454-808d91bf4dd8",
      "name": "Registration Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        176,
        -16
      ],
      "parameters": {
        "path": "event-register",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "6305126d-eab7-49a6-98cf-2384615bdf76",
      "name": "Create Ticket Data",
      "type": "n8n-nodes-base.set",
      "position": [
        400,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "ticketId",
              "type": "string",
              "value": "={{ 'TKT-' + $json.body.eventId + '-' + $now.format('HHmmssSSS') }}"
            },
            {
              "id": "2",
              "name": "eventId",
              "type": "string",
              "value": "={{ $json.body.eventId }}"
            },
            {
              "id": "3",
              "name": "participantName",
              "type": "string",
              "value": "={{ $json.body.name }}"
            },
            {
              "id": "4",
              "name": "email",
              "type": "string",
              "value": "={{ $json.body.email }}"
            },
            {
              "id": "5",
              "name": "ticketType",
              "type": "string",
              "value": "={{ $json.body.ticketType || 'standard' }}"
            },
            {
              "id": "6",
              "name": "registeredAt",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "7",
              "name": "checkedIn",
              "type": "string",
              "value": "no"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e9a53078-081a-4cf2-8bad-47b0b6fc94c0",
      "name": "Save to Participants Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        624,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $json.participantName }}",
            "Email": "={{ $json.email }}",
            "Event ID": "={{ $json.eventId }}",
            "Ticket ID": "={{ $json.ticketId }}",
            "Checked In": "={{ $json.checkedIn }}",
            "Ticket Type": "={{ $json.ticketType }}",
            "Check-in Time": "",
            "Registered At": "={{ $json.registeredAt }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Participants"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "5cce1cc0-faf8-4527-9eee-37f9e75ab31a",
      "name": "Prepare QR Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        -16
      ],
      "parameters": {
        "jsCode": "const ticket = $input.first().json;\n\nconst qrPayload = JSON.stringify({\n  t: ticket.ticketId,\n  e: ticket.eventId,\n  n: ticket.participantName.substring(0, 20),\n  ts: Date.now()\n});\n\nconst encodedPayload = Buffer.from(qrPayload).toString('base64');\n\nreturn [{\n  json: {\n    ...ticket,\n    qrData: encodedPayload,\n    qrContent: `https://event.company.com/checkin?code=${encodedPayload}`\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "044255d1-666d-46e1-ba77-0347a16078b7",
      "name": "Generate QR Code",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1056,
        -16
      ],
      "parameters": {
        "url": "=https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{ encodeURIComponent($json.qrContent) }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4096158e-0722-4bdb-98b3-cf25b7d61c56",
      "name": "Send Ticket Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1280,
        -16
      ],
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "message": "=Hello {{ $json.participantName }},\n\nThank you for registering!\n\nTicket ID: {{ $json.ticketId }}\nTicket Type: {{ $json.ticketType }}\n\nPlease present the attached QR code at the venue entrance.",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "=Your Ticket for {{ $json.eventId }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "39756491-416a-454b-be79-b5a66dd0313f",
      "name": "Registration Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1504,
        -16
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: true, ticketId: $json.ticketId, message: 'Ticket sent to ' + $json.email }) }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "31ba1d12-9c7f-43ca-bc3b-00cf5118d869",
      "name": "Check-in Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        176,
        512
      ],
      "parameters": {
        "path": "event-checkin",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "c48a2ec3-6cca-4193-bc26-4577e4f88e86",
      "name": "Decode QR Code",
      "type": "n8n-nodes-base.code",
      "position": [
        384,
        512
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst qrCode = input.body?.code || input.body?.qrCode || '';\n\nif (!qrCode) {\n  return [{ json: { valid: false, error: 'No QR code provided' } }];\n}\n\ntry {\n  const decoded = Buffer.from(qrCode, 'base64').toString('utf8');\n  const payload = JSON.parse(decoded);\n  \n  return [{\n    json: {\n      valid: true,\n      ticketId: payload.t,\n      eventId: payload.e,\n      participantName: payload.n,\n      scanTime: new Date().toISOString()\n    }\n  }];\n} catch (e) {\n  return [{ json: { valid: false, error: 'Invalid QR code format' } }];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "2c87839a-641f-4c98-87a8-844b9ad03926",
      "name": "Is Valid QR?",
      "type": "n8n-nodes-base.if",
      "position": [
        608,
        512
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "valid",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.valid }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "61304708-30fd-4254-9009-59d738104e0c",
      "name": "Lookup Ticket in DB",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        832,
        400
      ],
      "parameters": {
        "operation": "getMany",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "ee2e1e8e-8f95-481f-adb0-098778cc016c",
      "name": "Validate Check-in",
      "type": "n8n-nodes-base.code",
      "position": [
        1056,
        400
      ],
      "parameters": {
        "jsCode": "const qrData = $('Decode QR Code').first().json;\nconst ticketRecords = $input.all();\n\nif (ticketRecords.length === 0) {\n  return [{ json: { allowed: false, reason: 'Ticket not found', ticketId: qrData.ticketId } }];\n}\n\nconst ticket = ticketRecords[0].json;\n\nif (ticket['Checked In'] === 'yes') {\n  return [{ json: { \n    allowed: false, \n    reason: 'Already checked in at ' + ticket['Check-in Time'],\n    ticketId: qrData.ticketId,\n    participantName: ticket.Name\n  } }];\n}\n\nreturn [{ json: {\n  allowed: true,\n  ticketId: qrData.ticketId,\n  eventId: ticket['Event ID'],\n  participantName: ticket.Name,\n  ticketType: ticket['Ticket Type'],\n  isVIP: ticket['Ticket Type']?.toLowerCase() === 'vip',\n  checkInTime: qrData.scanTime\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "74239af4-ebb7-4771-8f13-aee588c67605",
      "name": "Check-in Allowed?",
      "type": "n8n-nodes-base.if",
      "position": [
        1264,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "allowed",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.allowed }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "100b8983-8cba-4a66-9f0a-7ef4b621be0a",
      "name": "Mark as Checked In",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1488,
        304
      ],
      "parameters": {
        "columns": {
          "value": {
            "Ticket ID": "={{ $json.ticketId }}",
            "Checked In": "yes",
            "Check-in Time": "={{ $json.checkInTime }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Participants"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "1938e6f2-a284-443f-9799-dab383c43f32",
      "name": "Is VIP?",
      "type": "n8n-nodes-base.if",
      "position": [
        1712,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "vip",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isVIP }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4b2a9d05-8501-44ae-9556-1ec88156c2c2",
      "name": "Slack VIP Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        1936,
        208
      ],
      "parameters": {
        "text": "=:star: *VIP Arrival*\n{{ $json.participantName }} has arrived!\nTicket: {{ $json.ticketId }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "#event-vip"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "536b9854-756b-489f-a781-9ea15eb60c67",
      "name": "Merge VIP Path",
      "type": "n8n-nodes-base.merge",
      "position": [
        2144,
        304
      ],
      "parameters": {
        "mode": "chooseBranch"
      },
      "typeVersion": 3
    },
    {
      "id": "e27d9c5b-f24c-4c32-b48b-406e79c40438",
      "name": "Build Success Response",
      "type": "n8n-nodes-base.code",
      "position": [
        2368,
        304
      ],
      "parameters": {
        "jsCode": "const checkinData = $('Validate Check-in').first().json;\n\nconst mockAttendance = 245;\nconst capacity = 300;\nconst attendancePercent = (mockAttendance / capacity * 100).toFixed(1);\n\nreturn [{\n  json: {\n    status: 'success',\n    message: `Welcome, ${checkinData.participantName}!`,\n    ticketId: checkinData.ticketId,\n    ticketType: checkinData.ticketType,\n    checkInTime: checkinData.checkInTime,\n    attendanceCount: mockAttendance,\n    capacityPercent: parseFloat(attendancePercent)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "db1f12e8-a819-49dd-8c57-6fa1da26c0c8",
      "name": "Check-in Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2592,
        304
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "477702f1-5df6-48e3-b623-dc904858a2a2",
      "name": "Check-in Denied",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1488,
        512
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ status: 'denied', reason: $json.reason, ticketId: $json.ticketId }) }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "7cb84ed5-7834-4815-ae61-e0d09608b9cc",
      "name": "Invalid QR Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        832,
        608
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ status: 'error', error: $json.error }) }}"
      },
      "typeVersion": 1.1
    }
  ],
  "connections": {
    "Is VIP?": {
      "main": [
        [
          {
            "node": "Slack VIP Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge VIP Path",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Is Valid QR?": {
      "main": [
        [
          {
            "node": "Lookup Ticket in DB",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Invalid QR Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode QR Code": {
      "main": [
        [
          {
            "node": "Is Valid QR?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge VIP Path": {
      "main": [
        [
          {
            "node": "Build Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack VIP Alert": {
      "main": [
        [
          {
            "node": "Merge VIP Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check-in Webhook": {
      "main": [
        [
          {
            "node": "Decode QR Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate QR Code": {
      "main": [
        [
          {
            "node": "Send Ticket Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check-in Allowed?": {
      "main": [
        [
          {
            "node": "Mark as Checked In",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check-in Denied",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Ticket Email": {
      "main": [
        [
          {
            "node": "Registration Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Check-in": {
      "main": [
        [
          {
            "node": "Check-in Allowed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Ticket Data": {
      "main": [
        [
          {
            "node": "Save to Participants Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Checked In": {
      "main": [
        [
          {
            "node": "Is VIP?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare QR Payload": {
      "main": [
        [
          {
            "node": "Generate QR Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Ticket in DB": {
      "main": [
        [
          {
            "node": "Validate Check-in",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registration Webhook": {
      "main": [
        [
          {
            "node": "Create Ticket Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Success Response": {
      "main": [
        [
          {
            "node": "Check-in Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Participants Sheet": {
      "main": [
        [
          {
            "node": "Prepare QR Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}