This workflow corresponds to n8n.io template #10588 — we link there as the canonical source.
This workflow follows the Gmail → Google Drive 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "9d642cd1-88d1-4bc2-9ef6-2b570db71ce5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1552,
-784
],
"parameters": {
"width": 400,
"height": 796,
"content": "## How it works\n\nThis workflow generates professional invoices instantly when triggered by payment gateways, CRM systems, or forms. It validates invoice data, auto-generates unique invoice numbers, calculates line items and taxes, adds your company branding and bank details, creates a PDF with payment status badge (Paid/Unpaid/Partial), archives it to Google Drive, and emails it to the customer. Team notifications route through Slack based on payment status\u2014paid invoices get success alerts while unpaid/partial invoices get reminders with due dates for collections follow-up.\n\n## Setup steps\n\n1. **Configure webhook** - Connect from your payment system (Stripe/PayPal), CRM, or form tool\n2. **Customize company data** - Edit branding, bank details, and tax IDs in \"Enrich with Company Data\" node\n3. **Set tax rates** - Adjust default tax percentage in \"Validate Invoice Data\" node (currently 18%)\n4. **Add HTML to PDF API** - Get key at htmlcsstoimage.com (1-5\u00a2 per invoice)\n5. **Connect Google Drive** - Authenticate for invoice archival\n6. **Connect Gmail** - Authenticate for customer email delivery\n7. **Add Slack webhooks** - Get URLs from Slack for both notification nodes\n8. **Test with sample data** before connecting live payment system\n\n\ud83d\udca1 **Required data:** customerName, customerEmail, items array (description, quantity, rate), paymentStatus (paid/unpaid/partial)"
},
"typeVersion": 1
},
{
"id": "c14e603f-a354-4d88-acf1-9add2a915a6c",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"position": [
-944,
-80
],
"parameters": {
"path": "invoice-generator",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 1
},
{
"id": "7d53dd09-7f7f-4d00-8d13-f53892f61223",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-240
],
"parameters": {
"color": 7,
"width": 588,
"height": 384,
"content": "## Data Processing\n\nReceives invoice data, validates required fields, auto-generates invoice numbers, calculates line items/subtotals/taxes, adds company branding and bank details, then creates professional HTML with payment status badge and itemized pricing."
},
"typeVersion": 1
},
{
"id": "969158b3-3974-4206-a232-f52304683a09",
"name": "Validate Invoice Data",
"type": "n8n-nodes-base.code",
"position": [
-784,
-32
],
"parameters": {
"jsCode": "// Validate incoming invoice data\nconst item = $input.first().json;\n\n// Required fields validation\nconst requiredFields = ['customerName', 'customerEmail', 'items', 'paymentStatus'];\nconst missingFields = requiredFields.filter(field => !item[field] || (typeof item[field] === 'string' && item[field].trim() === ''));\n\n// Validate items array\nif (!item.items || !Array.isArray(item.items) || item.items.length === 0) {\n missingFields.push('items (must be array with at least one item)');\n}\n\nif (missingFields.length > 0) {\n throw new Error(`Missing required fields: ${missingFields.join(', ')}`);\n}\n\n// Validate email format\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nif (!emailRegex.test(item.customerEmail)) {\n throw new Error('Invalid email format for customerEmail');\n}\n\n// Validate payment status\nconst validStatuses = ['paid', 'unpaid', 'partial'];\nif (!validStatuses.includes(item.paymentStatus.toLowerCase())) {\n throw new Error('Invalid paymentStatus. Must be: paid, unpaid, or partial');\n}\n\n// Validate and calculate items\nfor (let i = 0; i < item.items.length; i++) {\n const lineItem = item.items[i];\n if (!lineItem.description || !lineItem.quantity || !lineItem.rate) {\n throw new Error(`Item ${i + 1} missing required fields (description, quantity, rate)`);\n }\n \n // Ensure numeric values\n lineItem.quantity = parseFloat(lineItem.quantity);\n lineItem.rate = parseFloat(lineItem.rate);\n \n // Calculate amount\n item.items[i].amount = lineItem.quantity * lineItem.rate;\n}\n\n// Generate invoice number if not provided\nif (!item.invoiceNumber) {\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0');\n item.invoiceNumber = `INV-${year}${month}-${random}`;\n}\n\n// Set invoice date if not provided\nif (!item.invoiceDate) {\n item.invoiceDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n}\n\n// Calculate due date if not provided (default 30 days)\nif (!item.dueDate) {\n const dueDays = item.paymentTermsDays || 30;\n const dueDate = new Date();\n dueDate.setDate(dueDate.getDate() + dueDays);\n item.dueDate = dueDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n}\n\n// Calculate subtotal\nitem.subtotal = item.items.reduce((sum, lineItem) => sum + lineItem.amount, 0);\n\n// Apply discount if provided\nitem.discountAmount = parseFloat(item.discountAmount) || 0;\nconst afterDiscount = item.subtotal - item.discountAmount;\n\n// Calculate tax (default 18% if not provided)\nitem.taxRate = parseFloat(item.taxRate) || 18;\nitem.taxAmount = (afterDiscount * item.taxRate) / 100;\n\n// Calculate total\nitem.total = afterDiscount + item.taxAmount;\n\n// Set currency defaults\nitem.currency = item.currency || 'USD';\nitem.currencySymbol = item.currencySymbol || '$';\n\n// Payment terms\nitem.paymentTerms = item.paymentTerms || 'Payment due within 30 days';\n\nreturn { json: item };"
},
"typeVersion": 2
},
{
"id": "92f92526-75c7-47c9-9183-39a9a5de3735",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
-320
],
"parameters": {
"color": 7,
"width": 424,
"height": 496,
"content": "## Smart Notifications\n\nRoutes Slack alerts based on payment status. Paid invoices get success notifications. Unpaid/partial invoices get reminders with due dates, enabling accounting team to prioritize collections follow-up."
},
"typeVersion": 1
},
{
"id": "2624ead6-7e79-4b13-80ba-0a753d39d17b",
"name": "Enrich with Company Data",
"type": "n8n-nodes-base.code",
"position": [
-624,
-80
],
"parameters": {
"jsCode": "// Add company information and branding\nconst item = $input.first().json;\n\n// Company information (customize these)\nconst companyDefaults = {\n companyName: item.companyName || 'Media Jade',\n companyAddress: item.companyAddress || '456 Company Street',\n companyCity: item.companyCity || 'San Francisco, CA 94105',\n companyEmail: item.companyEmail || 'user@example.com',\n companyPhone: item.companyPhone || '+1234567890',\n companyWebsite: item.companyWebsite || 'www.mediajde.com',\n companyLogo: item.companyLogo || '',\n \n // Tax registration numbers\n taxId: item.taxId || 'TAX-123456789',\n gstNumber: item.gstNumber || 'GST-987654321',\n \n // Bank details for payment\n bankName: item.bankName || 'Chase Bank',\n accountNumber: item.accountNumber || '****1234',\n routingNumber: item.routingNumber || '****5678',\n swiftCode: item.swiftCode || 'CHASUS33',\n \n // Payment links\n paymentLink: item.paymentLink || '',\n \n // Customer defaults\n customerCompany: item.customerCompany || '',\n customerAddress: item.customerAddress || '',\n customerCity: item.customerCity || '',\n customerPhone: item.customerPhone || '',\n \n // Invoice notes\n notes: item.notes || 'Thank you for your business!',\n termsConditions: item.termsConditions || 'Payment is due within the specified terms. Late payments may incur additional charges.'\n};\n\nreturn { json: { ...item, ...companyDefaults } };"
},
"typeVersion": 2
},
{
"id": "232fc78f-fbfd-444e-9a8a-ee9639d9e10d",
"name": "Generate Invoice HTML",
"type": "n8n-nodes-base.code",
"position": [
-432,
-80
],
"parameters": {
"jsCode": "// Generate professional invoice HTML\nconst item = $input.first().json;\n\n// Payment status styling\nconst getStatusColor = (status) => {\n const colors = {\n 'paid': { bg: '#10b981', text: 'PAID' },\n 'unpaid': { bg: '#ef4444', text: 'UNPAID' },\n 'partial': { bg: '#f59e0b', text: 'PARTIALLY PAID' }\n };\n return colors[status.toLowerCase()] || colors['unpaid'];\n};\n\nconst statusStyle = getStatusColor(item.paymentStatus);\n\nconst html = `\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>Invoice - ${item.invoiceNumber}</title>\n <style>\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: 'Inter', sans-serif; line-height: 1.6; color: #1f2937; background: #ffffff; }\n .container { max-width: 800px; margin: 0 auto; padding: 40px; }\n .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 3px solid #3b82f6; }\n .company-info { flex: 1; }\n .logo { max-width: 160px; height: auto; margin-bottom: 15px; }\n .company-name { color: #3b82f6; font-size: 26px; font-weight: 700; margin-bottom: 8px; }\n .company-details { font-size: 13px; color: #6b7280; line-height: 1.7; }\n .invoice-badge { text-align: right; }\n .invoice-title { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); color: white; padding: 12px 25px; border-radius: 8px; font-size: 22px; font-weight: 700; letter-spacing: 1.5px; margin-bottom: 12px; }\n .invoice-number { font-size: 15px; color: #1f2937; font-weight: 600; margin-bottom: 8px; }\n .payment-status { display: inline-block; padding: 6px 16px; border-radius: 20px; font-size: 12px; font-weight: 700; letter-spacing: 1px; color: white; background: ${statusStyle.bg}; margin-top: 8px; }\n .info-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 40px; }\n .info-card { background: #f8fafc; padding: 20px; border-radius: 10px; border: 1px solid #e2e8f0; }\n .info-card h3 { color: #3b82f6; font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 12px; border-bottom: 2px solid #3b82f6; padding-bottom: 8px; }\n .info-card p { font-size: 13px; color: #4b5563; margin: 6px 0; }\n .info-card .name { font-size: 16px; font-weight: 600; color: #1f2937; margin-bottom: 4px; }\n .items-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-bottom: 25px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06); border-radius: 10px; overflow: hidden; }\n .items-table thead { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); }\n .items-table th { padding: 14px; text-align: left; font-weight: 600; font-size: 13px; color: white; text-transform: uppercase; }\n .items-table tbody tr { background: white; }\n .items-table tbody tr:nth-child(even) { background: #f9fafb; }\n .items-table td { padding: 14px; border-bottom: 1px solid #e5e7eb; font-size: 13px; color: #374151; }\n .items-table tbody tr:last-child td { border-bottom: none; }\n .text-right { text-align: right; }\n .summary-section { margin-left: auto; width: 350px; }\n .summary-row { display: flex; justify-content: space-between; padding: 10px 0; font-size: 14px; color: #4b5563; }\n .summary-row.subtotal { font-weight: 500; border-top: 1px solid #e5e7eb; padding-top: 12px; }\n .summary-row.total { border-top: 3px solid #3b82f6; margin-top: 12px; padding-top: 15px; font-weight: 700; font-size: 18px; color: #1e40af; background: #eff6ff; padding: 15px; border-radius: 8px; }\n .payment-info { margin-top: 40px; padding: 25px; background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border-left: 5px solid #10b981; border-radius: 8px; }\n .payment-info h3 { color: #065f46; font-size: 16px; font-weight: 700; margin-bottom: 15px; }\n .payment-info p { color: #047857; font-size: 13px; margin: 6px 0; }\n .payment-info strong { color: #064e3b; }\n .notes-section { margin-top: 30px; padding: 20px; background: #fef3c7; border-left: 4px solid #f59e0b; border-radius: 6px; }\n .notes-section h3 { color: #92400e; font-size: 14px; font-weight: 700; margin-bottom: 10px; }\n .notes-section p { color: #78350f; font-size: 13px; line-height: 1.6; }\n .footer { margin-top: 40px; padding-top: 20px; border-top: 2px solid #e5e7eb; text-align: center; color: #6b7280; font-size: 12px; }\n .footer p { margin: 5px 0; }\n @media print { body { print-color-adjust: exact; -webkit-print-color-adjust: exact; } }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <div class=\"company-info\">\n ${item.companyLogo ? `<img src=\"${item.companyLogo}\" alt=\"${item.companyName}\" class=\"logo\">` : `<h1 class=\"company-name\">${item.companyName}</h1>`}\n <div class=\"company-details\">\n ${item.companyAddress}<br>\n ${item.companyCity}<br>\n ${item.companyEmail} | ${item.companyPhone}<br>\n ${item.companyWebsite}\n </div>\n </div>\n <div class=\"invoice-badge\">\n <div class=\"invoice-title\">INVOICE</div>\n <div class=\"invoice-number\">${item.invoiceNumber}</div>\n <div class=\"payment-status\">${statusStyle.text}</div>\n </div>\n </div>\n\n <div class=\"info-grid\">\n <div class=\"info-card\">\n <h3>Bill To</h3>\n <p class=\"name\">${item.customerName}</p>\n ${item.customerCompany ? `<p><strong>${item.customerCompany}</strong></p>` : ''}\n <p>${item.customerEmail}</p>\n ${item.customerPhone ? `<p>${item.customerPhone}</p>` : ''}\n ${item.customerAddress ? `<p>${item.customerAddress}</p>` : ''}\n ${item.customerCity ? `<p>${item.customerCity}</p>` : ''}\n </div>\n <div class=\"info-card\">\n <h3>Invoice Details</h3>\n <p><strong>Invoice Date:</strong> ${item.invoiceDate}</p>\n <p><strong>Due Date:</strong> ${item.dueDate}</p>\n <p><strong>Payment Terms:</strong> ${item.paymentTerms}</p>\n ${item.purchaseOrderNumber ? `<p><strong>PO Number:</strong> ${item.purchaseOrderNumber}</p>` : ''}\n </div>\n </div>\n\n <table class=\"items-table\">\n <thead>\n <tr>\n <th style=\"width: 50%;\">Description</th>\n <th class=\"text-right\" style=\"width: 15%;\">Quantity</th>\n <th class=\"text-right\" style=\"width: 17%;\">Rate</th>\n <th class=\"text-right\" style=\"width: 18%;\">Amount</th>\n </tr>\n </thead>\n <tbody>\n ${item.items.map(lineItem => `\n <tr>\n <td>${lineItem.description}</td>\n <td class=\"text-right\">${lineItem.quantity}</td>\n <td class=\"text-right\">${item.currencySymbol}${lineItem.rate.toFixed(2)}</td>\n <td class=\"text-right\"><strong>${item.currencySymbol}${lineItem.amount.toFixed(2)}</strong></td>\n </tr>\n `).join('')}\n </tbody>\n </table>\n\n <div class=\"summary-section\">\n <div class=\"summary-row subtotal\">\n <span>Subtotal:</span>\n <span>${item.currencySymbol}${item.subtotal.toFixed(2)}</span>\n </div>\n ${item.discountAmount > 0 ? `\n <div class=\"summary-row\">\n <span>Discount:</span>\n <span>-${item.currencySymbol}${item.discountAmount.toFixed(2)}</span>\n </div>\n ` : ''}\n <div class=\"summary-row\">\n <span>Tax (${item.taxRate}%):</span>\n <span>${item.currencySymbol}${item.taxAmount.toFixed(2)}</span>\n </div>\n <div class=\"summary-row total\">\n <span>Total Amount:</span>\n <span>${item.currencySymbol}${item.total.toFixed(2)}</span>\n </div>\n </div>\n\n <div class=\"payment-info\">\n <h3>\ud83d\udcb3 Payment Information</h3>\n <p><strong>Bank Name:</strong> ${item.bankName}</p>\n <p><strong>Account Number:</strong> ${item.accountNumber}</p>\n <p><strong>Routing Number:</strong> ${item.routingNumber}</p>\n ${item.swiftCode ? `<p><strong>SWIFT Code:</strong> ${item.swiftCode}</p>` : ''}\n ${item.taxId ? `<p><strong>Tax ID:</strong> ${item.taxId}</p>` : ''}\n ${item.gstNumber ? `<p><strong>GST Number:</strong> ${item.gstNumber}</p>` : ''}\n ${item.paymentLink ? `<p style=\"margin-top: 12px;\"><strong>\ud83d\udcb0 Pay Online:</strong> <a href=\"${item.paymentLink}\" style=\"color: #047857; text-decoration: underline;\">${item.paymentLink}</a></p>` : ''}\n </div>\n\n ${item.notes ? `\n <div class=\"notes-section\">\n <h3>\ud83d\udcdd Notes</h3>\n <p>${item.notes}</p>\n </div>\n ` : ''}\n\n <div class=\"footer\">\n <p><strong>${item.companyName}</strong></p>\n <p>${item.termsConditions}</p>\n <p style=\"margin-top: 10px;\">Questions? Contact us at ${item.companyEmail} or ${item.companyPhone}</p>\n </div>\n </div>\n</body>\n</html>\n`;\n\nreturn {\n json: {\n html: html,\n invoiceNumber: item.invoiceNumber,\n customerName: item.customerName,\n customerEmail: item.customerEmail,\n total: item.total,\n currency: item.currency,\n paymentStatus: item.paymentStatus,\n fileName: `Invoice_${item.invoiceNumber}_${item.customerName.replace(/[^a-zA-Z0-9]/g, '_')}.pdf`,\n ...item\n }\n};"
},
"typeVersion": 2
},
{
"id": "88557c37-4406-49ea-92fb-1f96d7127f8d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-272,
-272
],
"parameters": {
"color": 7,
"width": 280,
"height": 340,
"content": "## PDF & Storage\n\nConverts HTML to print-ready PDF with preserved formatting, then archives to Google Drive with descriptive filename for searchability, compliance, and easy sharing."
},
"typeVersion": 1
},
{
"id": "fa21eb40-1c81-4c0c-8517-6b3305ba136f",
"name": "HTML to PDF",
"type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
"position": [
-256,
-80
],
"parameters": {},
"typeVersion": 1
},
{
"id": "268db052-2990-4760-8cc0-457aa25b3fdc",
"name": "Save to Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
-96,
-80
],
"parameters": {
"name": "={{ $('Generate Invoice HTML').item.json.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "root"
}
},
"typeVersion": 3
},
{
"id": "f1e750d4-15f7-4b59-8b9c-33e252677333",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
64,
-288
],
"parameters": {
"color": 7,
"width": 280,
"height": 368,
"content": "## Customer Delivery\n\nEmails invoice PDF to customer with payment instructions, bank details, and due date reminder. Instant delivery improves cash flow by reducing payment delays."
},
"typeVersion": 1
},
{
"id": "eaa80439-09ea-4ccc-91b1-030cc0b1e149",
"name": "Is Payment Received?",
"type": "n8n-nodes-base.if",
"position": [
432,
-80
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $('Generate Invoice HTML').item.json.paymentStatus }}",
"value2": "paid",
"operation": "equals"
}
]
}
},
"typeVersion": 1
},
{
"id": "f05925be-b9d1-428b-8e0a-a55c29854209",
"name": "Notify Team - Paid",
"type": "n8n-nodes-base.httpRequest",
"position": [
656,
-176
],
"parameters": {
"url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
"options": {},
"jsonBody": "={\n \"text\": \"\u2705 Invoice Paid & Delivered!\",\n \"blocks\": [\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*\ud83d\udcb0 Payment Received*\\n\\n*Invoice:* {{ $('Generate Invoice HTML').item.json.invoiceNumber }}\\n*Customer:* {{ $('Generate Invoice HTML').item.json.customerName }}\\n*Amount:* {{ $('Generate Invoice HTML').item.json.currency }} {{ $('Generate Invoice HTML').item.json.total }}\\n*Status:* PAID\\n\\n<{{ $('Save to Google Drive').item.json.webViewLink }}|View Invoice in Drive>\"\n }\n }\n ]\n}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.1
},
{
"id": "bed6dcd1-1c79-4fa9-8ac3-7f65e6168505",
"name": "Notify Team - Unpaid",
"type": "n8n-nodes-base.httpRequest",
"position": [
656,
32
],
"parameters": {
"url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
"options": {},
"jsonBody": "={\n \"text\": \"\u23f3 Invoice Sent - Payment Pending\",\n \"blocks\": [\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*\ud83d\udce4 Invoice Sent*\\n\\n*Invoice:* {{ $('Generate Invoice HTML').item.json.invoiceNumber }}\\n*Customer:* {{ $('Generate Invoice HTML').item.json.customerName }}\\n*Amount:* {{ $('Generate Invoice HTML').item.json.currency }} {{ $('Generate Invoice HTML').item.json.total }}\\n*Status:* {{ $('Generate Invoice HTML').item.json.paymentStatus }}\\n*Due Date:* {{ $('Generate Invoice HTML').item.json.dueDate }}\\n\\n<{{ $('Save to Google Drive').item.json.webViewLink }}|View Invoice in Drive>\"\n }\n }\n ]\n}",
"sendBody": true,
"specifyBody": "json"
},
"typeVersion": 4.1
},
{
"id": "3d20247f-67bf-40de-a517-591f63408bcd",
"name": "Send to Customer",
"type": "n8n-nodes-base.gmail",
"position": [
144,
-80
],
"parameters": {
"options": {}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"connections": {
"HTML to PDF": {
"main": [
[
{
"node": "Save to Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Webhook Trigger": {
"main": [
[
{
"node": "Validate Invoice Data",
"type": "main",
"index": 0
}
]
]
},
"Send to Customer": {
"main": [
[
{
"node": "Is Payment Received?",
"type": "main",
"index": 0
}
]
]
},
"Is Payment Received?": {
"main": [
[
{
"node": "Notify Team - Paid",
"type": "main",
"index": 0
}
],
[
{
"node": "Notify Team - Unpaid",
"type": "main",
"index": 0
}
]
]
},
"Save to Google Drive": {
"main": [
[
{
"node": "Send to Customer",
"type": "main",
"index": 0
}
]
]
},
"Generate Invoice HTML": {
"main": [
[
{
"node": "HTML to PDF",
"type": "main",
"index": 0
}
]
]
},
"Validate Invoice Data": {
"main": [
[
{
"node": "Enrich with Company Data",
"type": "main",
"index": 0
}
]
]
},
"Enrich with Company Data": {
"main": [
[
{
"node": "Generate Invoice HTML",
"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.
gmailOAuth2
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Transform invoice creation from 30 minutes to 30 seconds - automatically generate professional PDF invoices with tax calculations, payment tracking, and instant delivery via email while archiving to Google Drive and notifying your team based on payment status.
Source: https://n8n.io/workflows/10588/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
A comprehensive n8n workflow template that completely automates the startup pitch deck submission process for accelerators, incubators, VC firms, and startup competitions. This workflow validates foun
This workflow automates the entire parent consent process for school field trips, replacing manual paper forms with a secure, verified, and legally compliant digital system.
Transform new hire onboarding from 3-4 hours of manual document compilation to 3 minutes of automated generation - creates personalized, role-specific document packages including welcome letters, bene
Automatically generate professional PDF invoices when new orders are placed in Shopify. This template creates beautifully formatted invoices from order data, converts them to PDF, saves to Google Driv
Verified Corporate Training Certificate with CEUs – Fully Automated & Verifiable