{
  "id": "",
  "name": "certificate generator",
  "tags": [
    {
      "id": "CWzMtsCN0QfPR9PC",
      "name": "certificates",
      "createdAt": "2025-10-04T15:28:20.021Z",
      "updatedAt": "2025-10-04T15:28:20.021Z"
    },
    {
      "id": "qFR253LK8bI8GX4z",
      "name": "automation",
      "createdAt": "2025-10-04T15:28:20.027Z",
      "updatedAt": "2025-10-04T15:28:20.027Z"
    }
  ],
  "nodes": [
    {
      "id": "8aef6c7c-9dfd-483b-9b66-ee9a21ad0e3b",
      "name": "Credentials Setup Guide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3024,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 452,
        "height": 856,
        "content": "## \ud83d\udd27 CREDENTIALS SETUP REQUIRED\n\nBefore activating this workflow, configure these credentials:\n\n1. VerifiEmail API\n   - Sign up at https://verifi.email\n   - Get your API key from dashboard\n   - In n8n: Add VerifiEmail credential\n   - Paste API key\n\n2. HTMLcsstoImage API\n   - Sign up at https://htmlcsstoimg.com\n   - Get User ID and API Key\n   - In n8n: Add HTMLcsstoImg credential\n   - Enter User ID and API Key\n\n3. Gmail OAuth2 (for sending emails)\n   - Go to Settings > Credentials\n   - Add Gmail OAuth2\n   - Follow Google OAuth setup\n   - Grant necessary permissions\n   - Test connection\n\n4. Google Sheets OAuth2 (for logging)\n   - Add Google Sheets OAuth2 credential\n   - Create spreadsheet: \"Certificates Log\"\n   - Add these column headers:\n     \u2022 Certificate ID\n     \u2022 Recipient Name\n     \u2022 Course\n     \u2022 Email\n     \u2022 Completion Date\n     \u2022 Generated At\n     \u2022 Certificate URL\n     \u2022 Status\n     \u2022 Instructor\n     \u2022 Duration\n\n\u2705 All credentials configured in this workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "713712a6-27e5-482b-8994-eae001ab2785",
      "name": "Webhook Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2512,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 444,
        "height": 628,
        "content": "## \ud83d\udce5 WEBHOOK TRIGGER\n\nAccepts POST requests with certificate data\n\nRequired JSON format:\n```\n{\n  \"name\": \"John Doe\",\n  \"course\": \"Course Name\",\n  \"date\": \"2025-10-04\",\n  \"email\": \"user@example.com\"\n}\n```\nOptional fields:\n```\n{\n  \"instructor\": \"Jane Smith\",\n  \"duration\": \"40 hours\",\n  \"certificateId\": \"CERT-2025-001\"\n}\n```\n\ud83d\udd17 Your Webhook URL:\n```https://n8n.exildraw.com/webhook-test/certificate-generator```\n\n\ud83d\udcdd All data is accessed via:\n{{ $json.body.fieldName }}"
      },
      "typeVersion": 1
    },
    {
      "id": "a8b8e036-c01d-4091-b817-43611a1e2643",
      "name": "Certificate Request Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2192,
        544
      ],
      "parameters": {
        "path": "certificate-generator",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2
    },
    {
      "id": "3129040e-f390-4661-b17a-32b5c029cd8b",
      "name": "Email Validation Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2016,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 548,
        "content": "## \ud83d\udce7 EMAIL VALIDATION STEP\n\nUses VerifiEmail API to validate recipient email\n\nChecks performed:\n\u2713 RFC Compliance (proper email format)\n\u2713 Valid MX Records (domain accepts email)\n\u2713 Spoof Detection (checks for fake domains)\n\u2713 Disposable Email Detection (blocks temp emails)\n\nOutput includes:\n\u2022 valid: true/false\n\u2022 provider: email service provider\n\u2022 MX records: mail server details\n\n\u26a0\ufe0f Credential Required: VerifiEmail API key\n\nNext Step: IF node validates this + other fields"
      },
      "typeVersion": 1
    },
    {
      "id": "5c1071ea-cc45-49b2-9498-083d3a09508b",
      "name": "Validation Logic",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1584,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 360,
        "height": 596,
        "content": "## \u2705 VALIDATION CHECKPOINT\n\nChecks ALL required conditions:\n\nFrom Webhook:\n1. Name is not empty\n2. Course is not empty\n3. Date is not empty\n\nFrom VerifiEmail:\n4. Email validation = true\n\nAll conditions must pass (AND logic)\n\n\u2713 TRUE \u2192 Continue to Combine Data\n\u2717 FALSE \u2192 Stop workflow with error\n\nAccessing data:\n\u2022 Webhook: $('Certificate Request Webhook').item.json.body.field\n\u2022 Email: $json.valid"
      },
      "typeVersion": 1
    },
    {
      "id": "745c8af8-c38e-4257-968d-c8abeb30e5d3",
      "name": "Data Combination Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1184,
        -32
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 716,
        "content": "## \ud83d\udd04 COMBINE WEBHOOK + EMAIL DATA\n\nMerges certificate data with email validation results\n\nInput sources:\n\u2022 Webhook data: name, course, date, email, instructor, duration\n\u2022 Email validation: valid, provider, MX records\n\nOutput structure:\n```\n{\n  name, course, date, email,\n  instructor, duration, certificateId,\n  emailValidation: {\n    valid, provider, rfcCompliant,\n    validMxRecord, disposable\n  }\n}\n```\nPurpose: Creates clean data structure for HTML generation\n\n\u26a1 Auto-generates certificateId if not provided\n\ud83d\udcc5 Keeps original date format for later formatting"
      },
      "typeVersion": 1
    },
    {
      "id": "99566da7-4b33-4df0-a280-5a5db861bf13",
      "name": "HTML Generation Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 724,
        "content": "## \ud83c\udfa8 HTML CERTIFICATE GENERATOR\n\nCreates beautiful HTML certificate with:\n\nDesign Features:\n\u2022 Purple gradient background (#667eea \u2192 #764ba2)\n\u2022 Professional typography (Playfair Display + Montserrat)\n\u2022 Gold achievement badge with star\n\u2022 Clean white certificate with borders\n\u2022 Signature section with instructor name\n\u2022 Formatted completion date\n\nDynamic Content:\n\u2022 Recipient name (large, centered)\n\u2022 Course name\n\u2022 Completion date (formatted as \"Month Day, Year\")\n\u2022 Certificate ID (bottom right)\n\u2022 Instructor name (or \"Program Director\" if not provided)\n\u2022 Duration (optional, shown if provided)\n\nAuto-generates:\n\u2022 Unique Certificate ID if not provided\n\u2022 Format: CERT-{timestamp}-{random}\n\nOutput: Complete HTML ready for image conversion"
      },
      "typeVersion": 1
    },
    {
      "id": "d2f582b7-9d23-43b9-bc05-e50f96ad122f",
      "name": "Generate HTML Certificate",
      "type": "n8n-nodes-base.code",
      "position": [
        -640,
        528
      ],
      "parameters": {
        "jsCode": "// Certificate HTML Generator\nconst items = $input.all();\n\nreturn items.map(item => {\n  const data = item.json;\n  \n  // Generate unique certificate ID if not provided\n  const certId = data.certificateId || `CERT-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`;\n  \n  // Format date nicely\n  const certDate = new Date(data.date).toLocaleDateString('en-US', {\n    year: 'numeric',\n    month: 'long',\n    day: 'numeric'\n  });\n  \n  // HTML Template with inline CSS\n  const htmlContent = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Certificate of Completion</title>\n    <style>\n        @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Montserrat:wght@300;400;600&display=swap');\n        \n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n        \n        body {\n            width: 1200px;\n            height: 850px;\n            font-family: 'Montserrat', sans-serif;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            padding: 40px;\n        }\n        \n        .certificate {\n            background: white;\n            width: 100%;\n            height: 100%;\n            border: 20px solid #f8f9fa;\n            box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n            position: relative;\n            padding: 60px 80px;\n            display: flex;\n            flex-direction: column;\n            justify-content: space-between;\n        }\n        \n        .certificate::before {\n            content: '';\n            position: absolute;\n            top: 35px;\n            left: 35px;\n            right: 35px;\n            bottom: 35px;\n            border: 3px solid #667eea;\n            pointer-events: none;\n        }\n        \n        .header {\n            text-align: center;\n            margin-bottom: 20px;\n        }\n        \n        .logo {\n            width: 80px;\n            height: 80px;\n            margin: 0 auto 15px;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            border-radius: 50%;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            color: white;\n            font-size: 36px;\n            font-weight: bold;\n        }\n        \n        .title {\n            font-family: 'Playfair Display', serif;\n            font-size: 48px;\n            font-weight: 700;\n            color: #2d3748;\n            letter-spacing: 2px;\n            margin-bottom: 10px;\n        }\n        \n        .subtitle {\n            font-size: 18px;\n            color: #718096;\n            text-transform: uppercase;\n            letter-spacing: 3px;\n            font-weight: 300;\n        }\n        \n        .content {\n            text-align: center;\n            flex-grow: 1;\n            display: flex;\n            flex-direction: column;\n            justify-content: center;\n        }\n        \n        .presented-to {\n            font-size: 16px;\n            color: #718096;\n            text-transform: uppercase;\n            letter-spacing: 2px;\n            margin-bottom: 20px;\n        }\n        \n        .recipient-name {\n            font-family: 'Playfair Display', serif;\n            font-size: 56px;\n            font-weight: 700;\n            color: #667eea;\n            margin-bottom: 30px;\n            padding-bottom: 15px;\n            border-bottom: 3px solid #e2e8f0;\n            display: inline-block;\n            min-width: 500px;\n        }\n        \n        .description {\n            font-size: 18px;\n            color: #4a5568;\n            line-height: 1.8;\n            margin-bottom: 25px;\n            max-width: 700px;\n            margin-left: auto;\n            margin-right: auto;\n        }\n        \n        .course-name {\n            font-weight: 600;\n            color: #2d3748;\n            font-size: 24px;\n            margin: 20px 0;\n        }\n        \n        .footer {\n            display: flex;\n            justify-content: space-between;\n            align-items: flex-end;\n            margin-top: 40px;\n        }\n        \n        .signature-block {\n            text-align: center;\n            flex: 1;\n        }\n        \n        .signature-line {\n            border-top: 2px solid #2d3748;\n            width: 250px;\n            margin: 0 auto 10px;\n            padding-top: 5px;\n        }\n        \n        .signature-name {\n            font-weight: 600;\n            color: #2d3748;\n            font-size: 16px;\n            margin-bottom: 5px;\n        }\n        \n        .signature-title {\n            font-size: 14px;\n            color: #718096;\n        }\n        \n        .date-block {\n            text-align: center;\n        }\n        \n        .date-label {\n            font-size: 12px;\n            color: #718096;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n            margin-bottom: 5px;\n        }\n        \n        .date-value {\n            font-weight: 600;\n            color: #2d3748;\n            font-size: 16px;\n        }\n        \n        .cert-id {\n            position: absolute;\n            bottom: 15px;\n            right: 25px;\n            font-size: 10px;\n            color: #a0aec0;\n            letter-spacing: 1px;\n        }\n        \n        .badge {\n            position: absolute;\n            top: 50px;\n            right: 60px;\n            width: 100px;\n            height: 100px;\n            background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);\n            border-radius: 50%;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            box-shadow: 0 4px 15px rgba(255, 215, 0, 0.4);\n        }\n        \n        .badge::before {\n            content: '\u2605';\n            font-size: 50px;\n            color: white;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"certificate\">\n        <div class=\"badge\"></div>\n        \n        <div class=\"header\">\n            <div class=\"logo\">C</div>\n            <h1 class=\"title\">Certificate of Completion</h1>\n            <p class=\"subtitle\">This certifies that</p>\n        </div>\n        \n        <div class=\"content\">\n            <div class=\"recipient-name\">${data.name}</div>\n            \n            <p class=\"description\">\n                has successfully completed the course\n            </p>\n            \n            <div class=\"course-name\">${data.course}</div>\n            \n            ${data.duration ? `<p class=\"description\" style=\"margin-top: 10px; font-size: 16px;\">Duration: ${data.duration}</p>` : ''}\n        </div>\n        \n        <div class=\"footer\">\n            <div class=\"signature-block\">\n                <div class=\"signature-line\"></div>\n                <div class=\"signature-name\">${data.instructor || 'Program Director'}</div>\n                <div class=\"signature-title\">Instructor</div>\n            </div>\n            \n            <div class=\"date-block\">\n                <div class=\"date-label\">Date of Completion</div>\n                <div class=\"date-value\">${certDate}</div>\n            </div>\n        </div>\n        \n        <div class=\"cert-id\">Certificate ID: ${certId}</div>\n    </div>\n</body>\n</html>\n  `;\n  \n  return {\n    json: {\n      ...data,\n      certificateId: certId,\n      html: htmlContent,\n      formattedDate: certDate\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "9e764afe-be0f-4a6a-b5fc-4e2213353ae4",
      "name": "Image Conversion Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 704,
        "content": "## IMAGE CONVERSION\n\nConverts HTML certificate to high-quality PNG image\n\nService: HTMLcsstoImg API\nAPI Endpoint: hcti.io\n\nConfiguration:\n\u2022 Input: {{ $json.html }}\n\u2022 Google Fonts: Playfair Display|Montserrat\n\u2022 Output: PNG image\n\u2022 Resolution: 1200x850px\n\nAPI Response:\n```\n{\n  \"image_url\": \"https://hcti.io/v1/image/[id]\",\n  \"image_id\": \"[unique-id]\"\n}\n```\n\u26a0\ufe0f Credential Required: HTMLcsstoImg API\n   User ID + API Key configured\n\n\u2705 Direct shareable URL returned\n\ud83d\udce5 Image hosted on HTMLcsstoImg servers\n\ud83d\udd17 Permanent URL (doesn't expire)"
      },
      "typeVersion": 1
    },
    {
      "id": "edac6e11-432b-42f2-9128-b39d4585bd5b",
      "name": "Email Delivery Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 808,
        "content": "## CERTIFICATE EMAIL DELIVERY\n\nSends professional congratulatory email via Gmail\n\nEmail Contents:\n\u2022 Subject: \"\ud83c\udf93 Congratulations! Your Certificate of Completion\"\n\u2022 HTML-formatted message with:\n  - Gradient header with recipient name\n  - Course details in styled box\n  - Download button with certificate URL\n  - Certificate details table\n  - Call-to-action to share on LinkedIn\n  - Professional footer\n\nData Sources:\n\u2022 Recipient: From \"Code in JavaScript\" node\n\u2022 Certificate details: From \"Generate HTML Certificate\" node\n\u2022 Certificate URL: From \"HTML/CSS to Image\" node\n\nVariables used:\n\u2022 {{ $('Generate HTML Certificate').item.json.name }}\n\u2022 {{ $('Generate HTML Certificate').item.json.course }}\n\u2022 {{ $('Generate HTML Certificate').item.json.certificateId }}\n\u2022 {{ $json.image_url }}\n\n\u26a0\ufe0f Credential: Gmail OAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "7acdd47b-7014-4e0f-8b44-5acf326412be",
      "name": "Send Certificate Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        288,
        528
      ],
      "parameters": {
        "sendTo": "={{ $('Code in JavaScript').item.json.email }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n    <style>\n        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 0; }\n        .container { max-width: 600px; margin: 0 auto; }\n        .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); \n                  color: white; padding: 40px 20px; text-align: center; }\n        .header h1 { margin: 0; font-size: 28px; }\n        .content { background: #f8f9fa; padding: 40px 30px; }\n        .content p { margin: 15px 0; }\n        .course-box { background: white; border-left: 4px solid #667eea; \n                      padding: 20px; margin: 25px 0; border-radius: 5px; }\n        .course-box h2 { color: #667eea; margin: 0 0 10px 0; font-size: 22px; }\n        .button { background: #667eea; color: white; padding: 15px 30px; \n                  text-decoration: none; border-radius: 5px; display: inline-block; \n                  margin: 20px 0; font-weight: bold; }\n        .button:hover { background: #5568d3; }\n        .details { background: white; padding: 20px; border-radius: 5px; margin: 20px 0; }\n        .details ul { list-style: none; padding: 0; }\n        .details li { padding: 8px 0; border-bottom: 1px solid #e2e8f0; }\n        .details li:last-child { border-bottom: none; }\n        .details strong { color: #667eea; }\n        .footer { text-align: center; padding: 30px 20px; color: #718096; font-size: 14px; }\n        .footer p { margin: 5px 0; }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <div class=\"header\">\n            <h1>\ud83c\udf89 Congratulations, {{ $('Generate HTML Certificate').item.json.name }} !</h1>\n            <p style=\"margin: 10px 0 0 0; font-size: 16px;\">You've successfully completed your course</p>\n        </div>\n        \n        <div class=\"content\">\n            <p>We're thrilled to celebrate your achievement! You have successfully completed:</p>\n            \n            <div class=\"course-box\">\n                <h2>{{ $('Generate HTML Certificate').item.json.course }}</h2>\n                <p style=\"margin: 0; color: #718096;\">Completion Date: {{ $('Generate HTML Certificate').item.json.formattedDate }}</p>\n            </div>\n            \n            <p>Your certificate is ready and available for download. Share your accomplishment with your professional network!</p>\n            \n            <div style=\"text-align: center;\">\n                <a href=\"{{ $json.image_url }}\" class=\"button\">\ud83d\udce5 Download Certificate</a>\n            </div>\n            \n            <div class=\"details\">\n                <p><strong>\ud83d\udccb Certificate Details:</strong></p>\n                <ul>\n                    <li><strong>Certificate ID:</strong>{{ $('Generate HTML Certificate').item.json.certificateId }} </li>\n                    <li><strong>Recipient:</strong>{{ $('Generate HTML Certificate').item.json.name }} </li>\n                    <li><strong>Course:</strong> {{ $('Generate HTML Certificate').item.json.course }}</li>\n                    <li><strong>Completion Date:</strong> {{ $('Generate HTML Certificate').item.json.formattedDate }}</li>\n                    {{ $json.duration ? '<li><strong>Duration:</strong> ' + $json.duration + '</li>' : '' }}\n                    {{ $json.instructor ? '<li><strong>Instructor:</strong> ' + $json.instructor + '</li>' : '' }}\n                </ul>\n            </div>\n            \n            <p><strong>\ud83d\udcbc Share Your Success:</strong></p>\n            <p>Don't forget to add this certificate to your LinkedIn profile and share it with your network to showcase your new skills!</p>\n            \n            <p style=\"margin-top: 30px; color: #718096; font-size: 14px;\">If you have any questions about your certificate, please don't hesitate to reach out to our support team.</p>\n        </div>\n        \n        <div class=\"footer\">\n            <p><strong>Thank you for learning with us!</strong></p>\n            <p>\u00a9 2025 Your Organization. All rights reserved.</p>\n            <p style=\"font-size: 12px; margin-top: 15px;\">Certificate verification available at: yoursite.com/verify</p>\n        </div>\n    </div>\n</body>\n</html>",
        "options": {},
        "subject": "\ud83c\udf93 Congratulations! Your Certificate of Completion"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "5820e8bb-2f26-4d04-8445-61ea99902d35",
      "name": "Database Logging Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 864,
        "content": "## GOOGLE SHEETS LOGGING\n\nRecords every certificate to spreadsheet for tracking\n\nSpreadsheet: \"Certificates Log\"\nSheet: Sheet1\n\nLogged Data (10 columns):\n1. Certificate ID - Unique identifier\n2. Recipient Name - Full name\n3. Course - Course/program name\n4. Email - Recipient email\n5. Completion Date - Original date from webhook\n6. Generated At - Current timestamp (ISO format)\n7. Certificate URL - Direct image link\n8. Status - Always \"Sent\"\n9. Instructor - Instructor name\n10. Duration - Course duration\n\nData Sources:\n\u2022 Most fields: From \"Generate HTML Certificate\" node\n\u2022 Certificate URL: From \"HTML/CSS to Image\" node\n\u2022 Generated At: {{ $now.toISO() }}\n\nOperation: Append or Update Row\nMatch Column: Certificate ID (prevents duplicates)\n\n\u26a0\ufe0f Credential: Google Sheets OAuth2 \n\nPurpose: Audit trail, analytics, certificate verification"
      },
      "typeVersion": 1
    },
    {
      "id": "37b407ee-9362-402a-b708-5c821e1e1116",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        752,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "Email": "={{ $('Generate HTML Certificate').item.json.email }}",
            "Course": "={{ $('Generate HTML Certificate').item.json.course }}",
            "Status": "Sent",
            "Duration": "={{ $('Generate HTML Certificate').item.json.duration }}",
            "Instructor": "={{ $('Generate HTML Certificate').item.json.instructor }}",
            "Generated At": "={{ $now.toISO() }}",
            "Certificate ID": "={{ $('Generate HTML Certificate').item.json.certificateId }}",
            "Recipient Name": "={{ $('Generate HTML Certificate').item.json.name }}",
            "Certificate URL": "={{ $('HTML/CSS to Image').item.json.image_url }}",
            "Completion Date ": "={{ $('Generate HTML Certificate').item.json.date }}"
          },
          "schema": [
            {
              "id": "Certificate ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Certificate ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Recipient Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Recipient Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Course",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Course",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Completion Date ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Completion Date ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Generated At",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Generated At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Certificate URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Certificate URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Instructor",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Instructor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Duration",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Duration",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Certificate ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultUrl": "",
          "cachedResultName": "Certificates Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "559bc397-1e64-4f9e-91e0-69f01a2de564",
      "name": "Success Response Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        352
      ],
      "parameters": {
        "color": 7,
        "width": 716,
        "height": 624,
        "content": "## \u26a0\ufe0f RECOMMENDED ADDITION\n\nMISSING: Success Response to Webhook\n\nCurrently, workflow completes but doesn't send response back to webhook caller.\n\nTo add:\n1. Add \"Respond to Webhook\" node\n   After \"Log to Google Sheets\"\n\n2. Configure response:\n   Response Code: 200\n   Response Body:\n   ```\n    {\n     \"success\": true,\n     \"message\": \"Certificate generated successfully!\",\n     \"certificateId\": \"{{ $('Generate HTML Certificate').item.json.certificateId }}\",\n     \"recipientEmail\": \"{{ $('Generate HTML Certificate').item.json.email }}\",\n     \"certificateUrl\": \"{{ $('HTML/CSS to Image').item.json.image_url }}\",\n     \"generatedAt\": \"{{ $now.toISO() }}\"\n   }\n    ```\nWhy it's important:\n\u2022 API integrations need confirmation\n\u2022 Useful for tracking in external systems\n\u2022 Provides certificate URL to caller\n\u2022 Better for automation workflows\n\nWithout it: Workflow succeeds but caller gets no response"
      },
      "typeVersion": 1
    },
    {
      "id": "bd541a23-e982-4b64-82e2-30aea3e7601d",
      "name": "Error Handling Info",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        1088
      ],
      "parameters": {
        "color": 7,
        "width": 472,
        "height": 564,
        "content": "## \u26a0\ufe0f ERROR HANDLING\n\nWorkflow includes error catching and notification\n\nError Trigger:\n\u2022 Catches any workflow errors\n\u2022 Activates separate error flow\n\nError Processing:\n1. Format Error Details (Code node)\n   - Extracts error message\n   - Identifies failed node\n   - Captures user data (name, email, course)\n   - Logs execution ID and timestamp\n\n2. Send Slack Alert (DISABLED)\n   - Would notify admin team\n   - Enable if you have Slack integration\n   - Shows error details and user info\n\nNote: Slack alert currently disabled\nTo enable: Configure Slack credential and enable node\n\nMissing: Error response to webhook caller\nRecommendation: Add \"Respond to Webhook\" node after error trigger to return 500 status code"
      },
      "typeVersion": 1
    },
    {
      "id": "429a6ac5-d269-4176-ac81-d65117df54dd",
      "name": "On Workflow Error",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        -1680,
        1216
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e3cc736c-3a91-42d5-9037-5ffcad3e8cab",
      "name": "Format Error Details",
      "type": "n8n-nodes-base.code",
      "position": [
        -1472,
        1216
      ],
      "parameters": {
        "jsCode": "// Extract error information\nconst errorData = $input.first().json;\n\nreturn [{\n  json: {\n    errorMessage: errorData.error?.message || 'Unknown error occurred',\n    errorNode: errorData.node?.name || 'Unknown node',\n    timestamp: new Date().toISOString(),\n    workflowId: $workflow.id,\n    workflowName: $workflow.name,\n    executionId: $execution.id,\n    userData: {\n      name: errorData.json?.name || 'N/A',\n      email: errorData.json?.email || 'N/A',\n      course: errorData.json?.course || 'N/A'\n    },\n    fullError: JSON.stringify(errorData, null, 2)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c1ec5078-2bc7-4f7d-b413-fa0ca7691a15",
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.slack",
      "notes": "Optional: Enable if you want Slack notifications",
      "disabled": true,
      "position": [
        -1280,
        1216
      ],
      "parameters": {
        "text": "=\ud83d\udea8 **Certificate Generation Failed**\n\n**Error:** {{ $json.errorMessage }}\n**Node:** {{ $json.errorNode }}\n**Time:** {{ $json.timestamp }}\n\n**User Details:**\n\u2022 Name: {{ $json.userData.name }}\n\u2022 Email: {{ $json.userData.email }}\n\u2022 Course: {{ $json.userData.course }}\n\n**Execution ID:** {{ $json.executionId }}\n**Workflow:** {{ $json.workflowName }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C12345",
          "cachedResultName": "alerts"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "7d756f81-a0ac-4b11-bf07-dded65a5070d",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3376,
        800
      ],
      "parameters": {
        "color": 7,
        "width": 444,
        "height": 760,
        "content": "## COMPLETE WORKFLOW STRUCTURE\n\nMain Certificate Generation Flow:\n\n1. \ud83d\udce5 Webhook Trigger\n   Receives JSON with certificate data\n\n2. \ud83d\udce7 Verifi Email\n   Validates email address with VerifiEmail API\n\n3. \u2705 IF Validation\n   Checks: email valid + name/course/date not empty\n\n4. \ud83d\udd04 Combine Data (Code node)\n   Merges webhook data + email validation\n\n5. \ud83c\udfa8 Generate HTML Certificate (Code node)\n   Creates beautiful HTML certificate\n\n6. \ud83d\uddbc\ufe0f HTML/CSS to Image\n   Converts HTML \u2192 PNG image\n\n7. \ud83d\udce7 Send Email (Gmail)\n   Delivers certificate to recipient\n\n8. \ud83d\udcca Log to Google Sheets\n   Records certificate details\n\nError Flow (Separate):\n\u2022 On Workflow Error \u2192 Format Error \u2192 Slack Alert\n\nStatus: \u2705 Fully functional workflow\nMissing: Success response to webhook (recommended)\n\nAll credentials configured and tested"
      },
      "typeVersion": 1
    },
    {
      "id": "7c4dc0c1-ae2b-4985-91de-a40356e28158",
      "name": "Testing Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2896,
        832
      ],
      "parameters": {
        "color": 7,
        "width": 568,
        "height": 856,
        "content": "## \ud83e\uddea TESTING YOUR WORKFLOW\n\nWebhook URL:\nhttps://n8n.exildraw.com/webhook-test/certificate-generator\n\nTest with cURL:\n```\ncurl -X POST https://n8n.exildraw.com/webhook-test/certificate-generator \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"Test User\",\n    \"course\": \"Advanced JavaScript Programming\",\n    \"date\": \"2025-10-04\",\n    \"email\": \"test@gmail.com\",\n    \"instructor\": \"Jane Smith\",\n    \"duration\": \"40 hours\"\n  }'\n```\nTest with Postman:\n1. Method: POST\n2. URL: [webhook URL above]\n3. Headers: Content-Type = application/json\n4. Body: Use JSON from curl example\n\nExpected Results:\n\u2705 Email validation passes\n\u2705 HTML certificate generated\n\u2705 Image created at HTMLcsstoImg\n\u2705 Email sent to recipient\n\u2705 Entry logged in Google Sheets\n\u2705 All nodes execute successfully\n\nValidation Test (should fail):\n\u2022 Missing required field\n\u2022 Invalid email format\n\u2022 Disposable email address\n\n\u26a0\ufe0f Note: Use real email addresses for testing\nexample.com won't pass MX record validation\n\nCurrent Status: All nodes configured and ready\nNext: Add \"Respond to Webhook\" for success response"
      },
      "typeVersion": 1
    },
    {
      "id": "b9b4ba6f-35ca-4733-9d0a-0e2a7da5b56e",
      "name": "HTML/CSS to Image",
      "type": "n8n-nodes-htmlcsstoimage.htmlCssToImage",
      "position": [
        -160,
        528
      ],
      "parameters": {
        "html_content": "={{ $json.html }}"
      },
      "credentials": {
        "htmlcsstoimgApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "de9c267d-d005-43d4-bbb3-c33370f9493a",
      "name": "Verifi Email",
      "type": "n8n-nodes-verifiemail.verifiEmail",
      "position": [
        -1872,
        544
      ],
      "parameters": {
        "email": "={{ $json.body.email }}"
      },
      "credentials": {
        "verifiEmailApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "646e0a7b-2cdc-48c0-8f15-5b7755e9e484",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -1392,
        544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "a39497f8-8b8a-4b3a-bc5f-3e8738fa4cbb",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $('Certificate Request Webhook').item.json.body.name }}",
              "rightValue": ""
            },
            {
              "id": "37e0295c-18b2-4d3f-998b-e9d669dd90f7",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $('Certificate Request Webhook').item.json.body.course }}",
              "rightValue": ""
            },
            {
              "id": "6ecb1197-b460-402e-99a1-00edb0d5150c",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $('Certificate Request Webhook').item.json.body.date }}",
              "rightValue": ""
            },
            {
              "id": "3828fe0a-7c6a-449a-b380-c754717e0731",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.valid }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9b7e5242-b3da-4552-b088-d585ffe7bcb0",
      "name": "Stop and Error",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        -1040,
        784
      ],
      "parameters": {
        "errorMessage": "=\"Missing required fields: name, course, date, or valid email\""
      },
      "typeVersion": 1
    },
    {
      "id": "b57d3884-9846-4b1f-9b00-ec378ea386ac",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        -1056,
        528
      ],
      "parameters": {
        "jsCode": "// Combine Webhook Data with Email Validation\n// Get the current item (from IF node - email validation data)\nconst emailData = $input.item.json;\n\n// Get the original webhook data from the first node\nconst webhookData = $('Certificate Request Webhook').first().json.body;\n\n// Combine everything\nreturn {\n  json: {\n    // Certificate data from webhook\n    name: webhookData.name,\n    course: webhookData.course,\n    date: webhookData.date,\n    email: webhookData.email,\n    instructor: webhookData.instructor || 'Program Director',\n    duration: webhookData.duration || '',\n    certificateId: webhookData.certificateId || '',\n    \n    // Email validation results (optional - for logging/debugging)\n    emailValidation: {\n      valid: emailData.valid,\n      provider: emailData.details.mx.provider,\n      rfcCompliant: emailData.details.rfcCompliant,\n      validMxRecord: emailData.details.validMxRecord,\n      disposable: emailData.details.disposable\n    }\n  }\n};"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Stop and Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verifi Email": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML/CSS to Image": {
      "main": [
        [
          {
            "node": "Send Certificate Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On Workflow Error": {
      "main": [
        [
          {
            "node": "Format Error Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Generate HTML Certificate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Error Details": {
      "main": [
        [
          {
            "node": "Send Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Certificate Email": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate HTML Certificate": {
      "main": [
        [
          {
            "node": "HTML/CSS to Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Certificate Request Webhook": {
      "main": [
        [
          {
            "node": "Verifi Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}