AutomationFlowsEmail & Gmail › Event Ticketing Backend: Auto Qr Tickets with Google Sheets & Gmail

Event Ticketing Backend: Auto Qr Tickets with Google Sheets & Gmail

ByKhairul Muhtadin @khmuhtadin on n8n.io

Ticketing Backend automates registration, QR-ticket generation, email delivery, and check-in validation using Google Sheets, Gmail, and a webhook scanner — reducing manual ticket prep from ~3 hours to under 5 minutes for 200 attendees. Time Savings: Automates ticket generation &…

Webhook trigger★★★★★ complexity35 nodesGoogle SheetsHTTP RequestGmail
Email & Gmail Trigger: Webhook Nodes: 35 Complexity: ★★★★★ Added:

This workflow corresponds to n8n.io template #9280 — we link there as the canonical source.

This workflow follows the Gmail → Google Sheets recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "INTOFdov9bwbgo9w",
  "name": "Ticketing Backend",
  "tags": [],
  "nodes": [
    {
      "id": "06cc3525-a2a8-4b35-8436-73d03e43dbc7",
      "name": "Get Tickets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -240,
        -96
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json.ticket_id }}",
              "lookupColumn": "Ticket ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2010454173,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=2010454173",
          "cachedResultName": "Tickets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "4fe22443-1f46-4c85-8b93-670e2dfff603",
      "name": "Parse Barcode",
      "type": "n8n-nodes-base.code",
      "position": [
        -448,
        -96
      ],
      "parameters": {
        "jsCode": "const data = $input.all()[0].json.body;\n\n// Parse the barcode JSON string\nlet ticketData;\ntry {\n  ticketData = JSON.parse(data.barcode);\n} catch (error) {\n  return [{\n    json: {\n      success: false,\n      message: \"Invalid QR code format\"\n    }\n  }];\n}\n\nreturn [{\n  json: {\n    ticket_id: ticketData.ticket_id,\n    event: ticketData.event,\n    name: ticketData.name,\n    email: ticketData.email,\n    ticket_number: ticketData.ticket_number,\n    total_tickets: ticketData.total_tickets,\n    scannedAt: data.scannedAt\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "2276b656-ea51-4570-8896-d1fe28ebee45",
      "name": "Ticket Available?",
      "type": "n8n-nodes-base.if",
      "position": [
        -48,
        -96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5d1d995d-3ee8-4b56-8555-9fe5b919497a",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $('Get Tickets').all().length }}",
              "rightValue": 0
            },
            {
              "id": "982727a9-3593-4d1c-9ab3-d1c26d0798fc",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json[\"Checked In\"] }}",
              "rightValue": "YES"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d5265744-f1a6-4590-9c45-462297c5b4c7",
      "name": "Parse Output",
      "type": "n8n-nodes-base.code",
      "position": [
        144,
        16
      ],
      "parameters": {
        "jsCode": "const getTicketsResult = $('Get Tickets').all();\nconst parsedData = $('Parse Barcode').first().json;\n\nlet errorMessage = \"Ticket tidak valid\";\nlet errorCode = \"INVALID_TICKET\";\n\n// Check if ticket exists but already checked in\nif (getTicketsResult.length > 0) {\n  const ticket = getTicketsResult[0].json;\n  if (ticket[\"Checked In\"] === \"YES\") {\n    errorMessage = `Ticket sudah di-scan pada ${ticket[\"Checkin TIme\"]}`;\n    errorCode = \"ALREADY_CHECKED_IN\";\n  }\n}\n\nreturn [{\n  json: {\n    success: false,\n    error_code: errorCode,\n    message: errorMessage,\n    ticket_id: parsedData.ticket_id\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "2638bce7-9b67-491a-9bc1-8ffa2d08d4f8",
      "name": "Already Checked IN",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        320,
        16
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.4
    },
    {
      "id": "81b4773f-4728-4413-8950-12d79a27d257",
      "name": "Checked IN",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        320,
        -176
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"success\": true,\n  \"message\": \"Check-in berhasil!\",\n  \"data\": {\n    \"ticket_id\": \"{{ $('Get Tickets').first().json['Ticket ID'] }}\",\n    \"name\": \"{{ $('Get Tickets').first().json.Nama }}\",\n    \"ticket_number\": \"{{ $('Get Tickets').first().json['Ticket Number'] }}\",\n    \"email\": \"{{ $('Get Tickets').first().json.Email }}\",\n    \"checked_in_at\": \"{{ $json[\"Checkin TIme\"] }}\"\n  }\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "8f9403c3-65b9-4a5b-956f-c31c1089c190",
      "name": "Update Ticket Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        144,
        -176
      ],
      "parameters": {
        "columns": {
          "value": {
            "Ticket ID": "={{ $json[\"Ticket ID\"] }}",
            "Checked In": "YES",
            "Checkin TIme": "={{ new Date($('SCAN TICKET').item.json.body.scannedAt).toLocaleString('en-GB', { hour12: false }).replace(',', '') }}"
          },
          "schema": [
            {
              "id": "Ticket ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Ticket ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Nama",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Nama",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ticket Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ticket Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Tickets",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Total Tickets",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Checked In",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Checked In",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Checkin TIme",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Checkin TIme",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Ticket ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2010454173,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=2010454173",
          "cachedResultName": "Tickets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b6b18e4b-f70e-4870-b649-83980feb360e",
      "name": "SCAN TICKET",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -656,
        -96
      ],
      "parameters": {
        "path": "v1/scanner",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "a77f808a-f8c8-4d68-9007-744aa8018245",
      "name": "Email exist?",
      "type": "n8n-nodes-base.if",
      "position": [
        -48,
        1168
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5d1d995d-3ee8-4b56-8555-9fe5b919497a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.row_number !== undefined }}",
              "rightValue": "undefined"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "08943fee-59bc-4aac-b9cf-80662be21dca",
      "name": "Get Participant",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -240,
        1168
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json.Email }}",
              "lookupColumn": "Email"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=0",
          "cachedResultName": "Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "86af65a2-c014-4714-be6d-16083640acb4",
      "name": "Validate Input",
      "type": "n8n-nodes-base.code",
      "position": [
        -688,
        1328
      ],
      "parameters": {
        "jsCode": "const data = $input.all()[0].json.body;\n\n// Validation\nconst errors = [];\n\nif (!data.nama || data.nama.trim() === '') {\n  errors.push('Nama wajib diisi');\n}\n\nif (!data.email || !data.email.includes('@')) {\n  errors.push('Email tidak valid');\n}\n\nif (!data.no_hp || data.no_hp.length < 10) {\n  errors.push('Nomor HP tidak valid');\n}\n\nif (!data.jumlah_tiket || data.jumlah_tiket < 1) {\n  errors.push('Jumlah tiket minimal 1');\n}\n\nif (!data.payment_method) {\n  errors.push('Payment method wajib dipilih');\n}\n\n// Return error if validation fails\nif (errors.length > 0) {\n  return [{\n    json: {\n      valid: false,\n      validation_error: true,\n      errors: errors\n    }\n  }];\n}\n\n// Transform data for sheet\nreturn [{\n  json: {\n    valid: true,\n    validation_error: false,\n    Nama: data.nama,\n    \"No Hp\": data.no_hp,\n    Email: data.email,\n    \"Jumlah TIket\": data.jumlah_tiket,\n    \"Harga Tiket\": data.total_price,\n    \"Payment Method \": data.payment_method,\n    \"Payment Status\": \"PENDING\",\n    \"Email Sent\": \"NO\",\n    \"Ticked ID\": \"\"\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "0bb8c7fa-59d8-4185-954f-3a0858924bc7",
      "name": "Validation Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -240,
        1344
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"success\": false,\n  \"error\": \"VALIDATION_ERROR\",\n  \"message\": \"Validasi gagal\",\n  \"errors\": [\"Email tidak valid\"]\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "76dbc60d-7078-4b6e-ad79-cbbcdde7a9e7",
      "name": "Valid Input?",
      "type": "n8n-nodes-base.if",
      "position": [
        -480,
        1328
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0248f448-237b-46da-86b8-cdc5058ec170",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              },
              "leftValue": "={{ $json.validation_error }}",
              "rightValue": "false"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "431640c5-e0a7-44e2-9b51-c11d0f6f6b6c",
      "name": "Already Registered",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        160,
        992
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "{\n  \"success\": false,\n  \"error\": \"DUPLICATE_EMAIL\",\n  \"message\": \"Email sudah terdaftar\",\n  \"existing_data\": {\n    \"nama\": \"khairul\",\n    \"payment_status\": \"PAID\",\n    \"jumlah_tiket\": 2\n  }\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "b9f61154-8a8b-4ea9-ae62-a1b9b316af72",
      "name": "Tiket Booked",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        368,
        1184
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"success\": true,\n  \"message\": \"Registrasi berhasil! Silakan lakukan pembayaran.\",\n  \"data\": {\n    \"nama\": \"{{ $json.Nama }}\",\n    \"email\": \"{{ $json.Email }}\",\n    \"jumlah_tiket\": {{ $json['Jumlah TIket'] }},\n    \"total_price\": {{ $json['Harga Tiket'] }},\n    \"payment_method\": \"{{ $json['Payment Method '] }}\",\n    \"payment_status\": \"PENDING\"\n  }\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "63255ef1-df60-41cf-a262-e45e61636139",
      "name": "Store Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        160,
        1184
      ],
      "parameters": {
        "columns": {
          "value": {
            "Nama": "={{ $('Validate Input').item.json.Nama }}",
            "Email": "={{ $('Validate Input').item.json.Email }}",
            "No Hp": "={{ $('Validate Input').item.json['No Hp'] }}",
            "Email Sent": "={{ $('Validate Input').item.json['Email Sent'] }}",
            "Harga Tiket": "={{ $('Validate Input').item.json['Harga Tiket'] }}",
            "Jumlah TIket": "={{ $('Validate Input').item.json['Jumlah TIket'] }}",
            "Payment Status": "={{ $('Validate Input').item.json['Payment Status'] }}",
            "Payment Method ": "={{ $('Validate Input').item.json['Payment Method '] }}"
          },
          "schema": [
            {
              "id": "Nama",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Nama",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "No Hp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "No Hp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Jumlah TIket",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Jumlah TIket",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Harga Tiket",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Harga Tiket",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Method ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Payment Method ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Payment Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email Sent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ticked ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ticked ID",
              "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/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=0",
          "cachedResultName": "Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f93e5fa3-4e4f-4909-9fbe-fb148cc743d3",
      "name": "REGISTER",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -912,
        1328
      ],
      "parameters": {
        "path": "v1/register",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "dd84a672-34c0-422d-a178-0a181fd37882",
      "name": "Get Rows",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -736,
        416
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=0",
          "cachedResultName": "Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "5d549b2f-14ca-4f42-b96d-8d01051c0351",
      "name": "Filter Paid Not Sent",
      "type": "n8n-nodes-base.filter",
      "position": [
        -512,
        416
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "75fc42dd-aeec-4109-970d-7eb026b6b097",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"Payment Status\"] }}",
              "rightValue": "PAID"
            },
            {
              "id": "70bf28b6-59dc-4acc-8908-5e521d83c4fa",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json[\"Email Sent\"] }}",
              "rightValue": "NO"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0adcf4d7-d1e6-4f8a-945a-b7346ffd69fc",
      "name": "Generate Ticket Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -752,
        640
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nconst output = [];\n\nfor (let i = 0; i < items.length; i++) {\n  const item = items[i].json;\n  \n  // Parse jumlah tiket\n  const jumlahTiket = parseInt(item[\"Jumlah TIket\"]) || 1;\n  \n  // Generate ALL ticket IDs first for this person\n  const allTicketsForThisPerson = [];\n  \n  for (let ticketNum = 1; ticketNum <= jumlahTiket; ticketNum++) {\n    const now = new Date();\n    const timestamp = now.toISOString().slice(0,10).replace(/-/g, '');\n    const rowNum = item.row_number || (i + 2);\n    const hash = Math.random().toString(36).substring(2, 10).toUpperCase();\n    \n    const ticketId = `TL-${timestamp}-${String(rowNum).padStart(4, '0')}-${ticketNum}-${hash}`;\n    allTicketsForThisPerson.push(ticketId);\n    \n    const qrData = JSON.stringify({\n      event: \"TABRAK_LARI\",\n      ticket_id: ticketId,\n      name: item.Nama,\n      email: item.Email,\n      ticket_number: ticketNum,\n      total_tickets: jumlahTiket,\n      timestamp: now.toISOString(),\n      hash: hash\n    });\n    \n    output.push({\n      json: {\n        ...item,\n        ticket_id: ticketId,\n        ticket_number: ticketNum,\n        total_tickets: jumlahTiket,\n        qr_data: qrData,\n        qr_data_url_encoded: encodeURIComponent(qrData),\n        event_name: \"TABRAK LARI\",\n        event_date: \"15 November 2025\",\n        event_location: \"GOR Pontianak\"\n      }\n    });\n  }\n}\n\nreturn output;"
      },
      "typeVersion": 2
    },
    {
      "id": "f9c1609a-b102-452f-972d-12625e9403c6",
      "name": "Generate QR Code",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -480,
        640
      ],
      "parameters": {
        "url": "=https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{ $json.qr_data_url_encoded }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "43c28eec-ecaa-4de2-aab6-c7efa392b232",
      "name": "Build HTML Email",
      "type": "n8n-nodes-base.code",
      "position": [
        -256,
        560
      ],
      "parameters": {
        "jsCode": "// Build HTML Ticket Email - MULTIPLE TICKETS SUPPORT\nconst items = $input.all();\nconst output = [];\n\nfor (let i = 0; i < items.length; i++) {\n  const item = items[i].json;\n  \n  // Get binary data\n  let qrBase64 = '';\n  \n  if (items[i].binary && items[i].binary.data) {\n    const binaryData = items[i].binary.data;\n    \n    if (binaryData.data) {\n      qrBase64 = binaryData.data;\n    } else if (Buffer.isBuffer(binaryData)) {\n      qrBase64 = binaryData.toString('base64');\n    }\n  }\n  \n  const htmlTemplate = `\n<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body {\n      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n      padding: 20px;\n      margin: 0;\n    }\n    .ticket-container {\n      max-width: 600px;\n      margin: 0 auto;\n      background: white;\n      border-radius: 20px;\n      overflow: hidden;\n      box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n    }\n    .ticket-header {\n      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n      color: white;\n      padding: 40px 30px;\n      text-align: center;\n    }\n    .ticket-header h1 {\n      margin: 0;\n      font-size: 32px;\n      font-weight: 700;\n      text-transform: uppercase;\n      letter-spacing: 2px;\n    }\n    .ticket-number-badge {\n      background: rgba(255,255,255,0.2);\n      display: inline-block;\n      padding: 8px 20px;\n      border-radius: 20px;\n      margin-top: 10px;\n      font-size: 14px;\n      font-weight: 600;\n    }\n    .ticket-body {\n      padding: 40px 30px;\n    }\n    .qr-section {\n      text-align: center;\n      margin: 30px 0;\n      padding: 30px;\n      background: #f8f9fa;\n      border-radius: 15px;\n    }\n    .qr-section img {\n      max-width: 280px;\n      border: 8px solid white;\n      border-radius: 10px;\n      box-shadow: 0 5px 15px rgba(0,0,0,0.1);\n    }\n    .ticket-info {\n      background: #f8f9fa;\n      padding: 25px;\n      border-radius: 15px;\n      margin: 20px 0;\n    }\n    .info-row {\n      display: flex;\n      justify-content: space-between;\n      padding: 12px 0;\n      border-bottom: 1px solid #dee2e6;\n    }\n    .info-row:last-child {\n      border-bottom: none;\n    }\n    .info-label {\n      font-weight: 600;\n      color: #495057;\n    }\n    .info-value {\n      color: #212529;\n      font-weight: 500;\n    }\n    .ticket-id {\n      text-align: center;\n      font-size: 20px;\n      font-weight: 700;\n      color: #667eea;\n      margin: 20px 0;\n      padding: 15px;\n      background: #f8f9fa;\n      border-radius: 10px;\n      letter-spacing: 1px;\n      word-break: break-all;\n    }\n    .important-note {\n      background: #fff3cd;\n      border-left: 4px solid #ffc107;\n      padding: 20px;\n      margin: 25px 0;\n      border-radius: 5px;\n    }\n    .important-note h3 {\n      margin-top: 0;\n      color: #856404;\n    }\n    .footer {\n      text-align: center;\n      padding: 30px;\n      color: #6c757d;\n      font-size: 14px;\n    }\n  </style>\n</head>\n<body>\n  <div class=\"ticket-container\">\n    <div class=\"ticket-header\">\n      <h1>${item.event_name}</h1>\n      <p style=\"margin: 10px 0 0 0; font-size: 18px;\">Tiketmu Telah Tersedia!</p>\n      <div class=\"ticket-number-badge\">\n        Tiket ${item.ticket_number} dari ${item.total_tickets}\n      </div>\n    </div>\n    \n    <div class=\"ticket-body\">\n      <h2 style=\"color: #212529; margin-top: 0;\">Hi ${item.Nama || item.Name || 'Guest'}!</h2>\n      <p style=\"color: #495057; font-size: 16px; line-height: 1.6;\">\n        Terima kasih atas pembayaran Anda! Berikut adalah tiket <strong>#${item.ticket_number}</strong> dari total <strong>${item.total_tickets} tiket</strong> yang Anda pesan.\n      </p>\n      \n      <div class=\"ticket-id\">\n        ${item.ticket_id}\n      </div>\n      \n      <div class=\"qr-section\">\n        <h3 style=\"margin-top: 0; color: #495057;\">Scan QR Code Ini di Entrance</h3>\n        <img src=\"data:image/png;base64,${qrBase64}\" alt=\"QR Code Ticket\" />\n      </div>\n      \n      <div class=\"ticket-info\">\n        <h3 style=\"margin-top: 0; color: #495057;\">Detail Tiket</h3>\n        <div class=\"info-row\">\n          <span class=\"info-label\">Nama:</span>\n          <span class=\"info-value\">${item.Nama || item.Name || 'Guest'}</span>\n        </div>\n        <div class=\"info-row\">\n          <span class=\"info-label\">Email:</span>\n          <span class=\"info-value\">${item.Email}</span>\n        </div>\n        <div class=\"info-row\">\n          <span class=\"info-label\">Tiket:</span>\n          <span class=\"info-value\">#${item.ticket_number} dari ${item.total_tickets}</span>\n        </div>\n        <div class=\"info-row\">\n          <span class=\"info-label\">Ticket ID:</span>\n          <span class=\"info-value\">${item.ticket_id}</span>\n        </div>\n      </div>\n      \n      <div class=\"important-note\">\n        <h3>Penting!</h3>\n        <ul style=\"margin: 10px 0; padding-left: 20px;\">\n          <li>Simpan email ini dengan baik</li>\n          <li>Setiap tiket memiliki QR code unik</li>\n          <li>Tunjukkan QR code saat masuk venue</li>\n          <li>Satu tiket hanya berlaku untuk satu kali scan</li>\n          <li>Datang 30 menit sebelum acara dimulai</li>\n        </ul>\n      </div>\n    </div>\n    \n    <div class=\"footer\">\n      <p style=\"margin: 5px 0;\">2025 TABRAK LARI Event. All rights reserved.</p>\n    </div>\n  </div>\n</body>\n</html>\n`;\n\n  output.push({\n    json: {\n      ...item,\n      html_content: htmlTemplate,\n      qr_base64: qrBase64\n    }\n  });\n}\n\nreturn output;"
      },
      "typeVersion": 2
    },
    {
      "id": "641a85a1-0f76-4894-bd17-c9715f39eea1",
      "name": "Send Email (Gmail)",
      "type": "n8n-nodes-base.gmail",
      "position": [
        0,
        384
      ],
      "parameters": {
        "sendTo": "={{ $json.Email }}",
        "message": "={{ $json.html_content }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Tiketmu Telah Tersedia!"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "bcfc2a0f-474b-4b9a-a652-52715cdf7e29",
      "name": "Update Sheet (Register)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        272,
        560
      ],
      "parameters": {
        "columns": {
          "value": {
            "Email": "={{ $json.Email }}",
            "Ticked ID": "={{ $json.ticket_ids_combined }}",
            "Email Sent": "YES"
          },
          "schema": [
            {
              "id": "Nama",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Nama",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "No Hp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "No Hp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Jumlah TIket",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Jumlah TIket",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Harga Tiket",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Harga Tiket",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Method ",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Payment Method ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Payment Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Payment Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email Sent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ticked ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Ticked ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Checked In?",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Checked In?",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "CHECKIN TIME",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "CHECKIN TIME",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=0",
          "cachedResultName": "Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "207cd6d4-0812-4547-8b28-c5c3725636bd",
      "name": "Update Sheet (Tickets)",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        16,
        736
      ],
      "parameters": {
        "columns": {
          "value": {
            "Nama": "={{ $json.Nama }}",
            "Email": "={{ $json.Email }}",
            "Ticket ID": "={{ $json.ticket_id }}",
            "Ticket Number": "={{ $json.ticket_number }}/{{ $json.total_tickets }}",
            "Total Tickets": "={{ $json.total_tickets }}"
          },
          "schema": [
            {
              "id": "Ticket ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ticket ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Nama",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Nama",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ticket Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ticket Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Tickets",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Total Tickets",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Checked In",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Checked In",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Checkin TIme",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Checkin TIme",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2010454173,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit#gid=2010454173",
          "cachedResultName": "Tickets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1rQqe5XWmhWgnsAI6Q8kxoeCTbcNMdHsfP2tHRP7y7Po/edit?usp=drivesdk",
          "cachedResultName": "TABRAK LARI"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f99c03de-9578-456f-8443-e5fa2840e88e",
      "name": "START",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -960,
        416
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 1
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "75d7c162-962b-4a07-80db-43ed07565987",
      "name": "Parse Data",
      "type": "n8n-nodes-base.code",
      "position": [
        16,
        560
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nconst grouped = {};\n\nfor (let item of items) {\n  const email = item.json.Email;\n  \n  if (!grouped[email]) {\n    grouped[email] = {\n      Email: email,\n      ticket_ids: []\n    };\n  }\n  \n  grouped[email].ticket_ids.push(item.json.ticket_id);\n}\n\nconst output = Object.values(grouped).map(item => ({\n  json: {\n    Email: item.Email,\n    ticket_ids_combined: item.ticket_ids.join(\", \")\n  }\n}));\n\nreturn output;"
      },
      "typeVersion": 2
    },
    {
      "id": "0b3858e2-2c61-4f1d-b6e6-45a7e3ce3ea6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1008,
        -352
      ],
      "parameters": {
        "width": 1552,
        "height": 608,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "7b512e89-2626-4a2b-b24e-a4688d9e120b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1008,
        288
      ],
      "parameters": {
        "color": 4,
        "width": 1552,
        "height": 608,
        "content": "# Ticket Generator & Sender\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cc7ab6b0-47ea-4e08-8ba8-5cbc0e470e2c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1008,
        928
      ],
      "parameters": {
        "color": 3,
        "width": 1552,
        "height": 608,
        "content": "\n"
      },
      "typeVersion": 1
    },
    {
      "id": "34074899-d8b0-4ae0-89be-3ac61046fd03",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        288
      ],
      "parameters": {
        "color": 5,
        "width": 512,
        "height": 608,
        "content": "# Event Ticketing System - Complete Flow\n\nThis workflow manages the full lifecycle of event ticketing:\n1. **Registration** - Accepts participant registration via webhook\n2. **Ticket Generation** - Auto-generates QR codes for paid registrations\n3. **Email Delivery** - Sends tickets to participants via Gmail\n4. **Check-in Scanner** - Validates tickets at the event entrance\n\nAll data is stored in Google Sheets with two tabs:\n- Register (participant info)\n- Tickets (individual ticket records)"
      },
      "typeVersion": 1
    },
    {
      "id": "33452a6b-f2cf-4acc-bfe1-fb2506e26cd6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        928
      ],
      "parameters": {
        "color": 5,
        "width": 512,
        "height": 608,
        "content": "# Setup Required\n\nYou need these credentials configured:\n\n1. **Google Sheets OAuth2** \n   - Used for reading/writing registration & ticket data\n   - Connect your Google account in n8n credentials\n\n2. **Gmail OAuth2**\n   - Used for sending ticket emails\n   - Must use the same Google account as Sheets\n   - Enable Gmail API in Google Cloud Console\n\n3. **Google Sheet Structure**\n   - Sheet ID: `your sheet id`\n   - Tab 1: \"Register\" - stores participant registrations\n   - Tab 2: \"Tickets\" - stores individual ticket records"
      },
      "typeVersion": 1
    },
    {
      "id": "160db932-0e42-4b39-b39d-2654179c1c78",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -992,
        -336
      ],
      "parameters": {
        "color": 5,
        "width": 480,
        "height": 496,
        "content": "# How Ticket Scanner Works\n\n**Endpoint**: POST `/v1/scanner`\n\n**Flow**:\n1. Receives scanned QR data\n2. Parses ticket_id from barcode JSON\n3. Looks up ticket in Google Sheets\n4. Validates:\n   - Ticket exists\n   - Not already checked in\n5. Updates \"Checked In\" = YES if valid\n6. Returns success/error response\n\n**Error Cases**:\n- Invalid ticket\n- Already checked in (shows previous check-in time)"
      },
      "typeVersion": 1
    },
    {
      "id": "84430c98-7876-4ea9-9908-7f59c7718752",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -992,
        944
      ],
      "parameters": {
        "color": 5,
        "width": 512,
        "height": 352,
        "content": "# Registration Endpoint\n\n**Endpoint**: POST `/v1/register`\n\n**Expected Input**:\n```json\n{\n  \"nama\": \"string\",\n  \"email\": \"string\", \n  \"no_hp\": \"string\",\n  \"jumlah_tiket\": number,\n  \"total_price\": number,\n  \"payment_method\": \"string\"\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "9cd7ba10-a91c-4134-a481-94df3bfde3c3",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        -352
      ],
      "parameters": {
        "color": 5,
        "width": 512,
        "height": 608,
        "content": "# Automatic Ticket Generation\n\n**Trigger**: Runs every 1 minute\n\n**What it does**:\n1. Finds paid registrations where Email Sent = NO\n2. Generates unique ticket IDs for each ticket\n3. Creates QR codes via qrserver.com API\n4. Builds HTML email with QR code embedded\n5. Sends one email per ticket (supports multiple tickets)\n6. Updates both Register & Tickets sheets\n7. Marks Email Sent = YES\n\n**Ticket ID Format**: \n`TL-YYYYMMDD-XXXX-N-HASH`\n- Event code, date, row number, ticket number, unique hash"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7577dfcb-a9b7-4cef-85ca-ecfc79c85cef",
  "connections": {
    "START": {
      "main": [
        [
          {
            "node": "Get Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Rows": {
      "main": [
        [
          {
            "node": "Filter Paid Not Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "REGISTER": {
      "main": [
        [
          {
            "node": "Validate Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Data": {
      "main": [
        [
          {
            "node": "Update Sheet (Register)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Data": {
      "main": [
        [
          {
            "node": "Tiket Booked",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Tickets": {
      "main": [
        [
          {
            "node": "Ticket Available?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SCAN TICKET": {
      "main": [
        [
          {
            "node": "Parse Barcode",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email exist?": {
      "main": [
        [
          {
            "node": "Already Registered",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Store Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Output": {
      "main": [
        [
          {
            "node": "Already Checked IN",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Valid Input?": {
      "main": [
        [
          {
            "node": "Get Participant",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Validation Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Barcode": {
      "main": [
        [
          {
            "node": "Get Tickets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input": {
      "main": [
        [
          {
            "node": "Valid Input?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Participant": {
      "main": [
        [
          {
            "node": "Email exist?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build HTML Email": {
      "main": [
        [
          {
            "node": "Send Email (Gmail)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Parse Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update Sheet (Tickets)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate QR Code": {
      "main": [
        [
          {
            "node": "Build HTML Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ticket Available?": {
      "main": [
        [
          {
            "node": "Update Ticket Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parse Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Paid Not Sent": {
      "main": [
        [
          {
            "node": "Generate Ticket Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Ticket Data": {
      "main": [
        [
          {
            "node": "Generate QR Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Ticket Status": {
      "main": [
        [
          {
            "node": "Checked IN",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Ticketing Backend automates registration, QR-ticket generation, email delivery, and check-in validation using Google Sheets, Gmail, and a webhook scanner — reducing manual ticket prep from ~3 hours to under 5 minutes for 200 attendees. Time Savings: Automates ticket generation &…

Source: https://n8n.io/workflows/9280/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

Automate WhatsApp communication for recruitment agencies with an interactive, structured customer experience. This workflow handles pricing inquiries, request submissions, tracking, complaints, and hu

HTTP Request, Google Sheets, Gmail +1
Email & Gmail

Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups,

Google Sheets, HTTP Request, Gmail +1
Email & Gmail

Streamline and standardize your entire client onboarding process with a single end-to-end automation. 🚀📋 This workflow captures detailed client intake data via webhook, automatically creates a fully s

Slack, Asana, HTTP Request +4
Email & Gmail

Human Approval AI Response. Uses httpRequest, slack, gmail, googleSheets. Webhook trigger; 20 nodes.

HTTP Request, Slack, Gmail +2
Email & Gmail

This n8n template automatically monitors website performance using Google's PageSpeed Insights API, compiles detailed reports, and tracks performance trends over time in Google Sheets.

HTTP Request, Google Sheets, Gmail