This workflow follows the Gmail → Gmail Trigger 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 →
{
"name": "W14 - Purchase Order Processor & Approval Workflow",
"nodes": [
{
"parameters": {
"content": "## \ud83d\udce6 Purchase Order Processor\n\n### What this workflow does\n1. Watches Gmail for PO attachments\n2. Extracts vendor, line items, totals\n3. Calculates approval level by amount\n4. Logs to Google Sheets tracker\n5. Sends Slack notification with details\n\n### Setup steps\n1. Get PDF Vector API key from pdfvector.com/api-keys\n2. Connect Gmail account\n3. Create Google Sheet with columns (see template)\n4. Connect Slack and set channel\n\n### Approval Thresholds\n- < $1,000: Auto-approve\n- $1,000-$4,999: Manager\n- $5,000-$24,999: Director\n- \u2265 $25,000: VP/CFO\n\n### Perfect for\n- Procurement teams\n- Finance departments\n- Operations managers",
"height": 480,
"width": 340,
"color": 5
},
"id": "sticky-main",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-260,
60
]
},
{
"parameters": {
"content": "## \u2705 Auto Validation\n\n- Approval level by amount\n- Urgency by delivery date\n- Line item totals\n- Missing field handling",
"height": 160,
"width": 220
},
"id": "sticky-validation",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
528,
60
]
},
{
"parameters": {
"content": "## \ud83d\udccb Extracted Fields\n\n- PO Number\n- Vendor details\n- Ship-to address\n- Line items array\n- Subtotal, tax, shipping\n- Grand total\n- Payment terms",
"height": 200,
"width": 220
},
"id": "sticky-fields",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
280,
60
]
},
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"filters": {
"includeSpamTrash": false
}
},
"id": "gmail-trigger",
"name": "Gmail Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"typeVersion": 1,
"position": [
100,
300
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "get",
"messageId": "={{ $json.id }}",
"simple": false,
"options": {
"dataPropertyAttachmentsPrefixName": "attachment_",
"downloadAttachments": true
}
},
"id": "gmail-get",
"name": "Get a message",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
280,
300
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "extract",
"inputType": "file",
"prompt": "Extract purchase order data as flat fields. poNumber, orderDate (YYYY-MM-DD), requiredDate (YYYY-MM-DD), vendorName, vendorAddress, vendorContact, vendorEmail, vendorPhone, shipToName, shipToAddress, shipToAttention, billToName, billToAddress, lineItemsList (semicolon-separated formatted as: qty x description @ unitPrice = total), lineItemCount (number), subtotal (number), shippingCost (number), tax (number), grandTotal (number), paymentTerms, shippingMethod, notes.",
"schema": "{\"type\": \"object\", \"properties\": {\"poNumber\": {\"type\": \"string\"}, \"orderDate\": {\"type\": \"string\"}, \"requiredDate\": {\"type\": \"string\"}, \"vendorName\": {\"type\": \"string\"}, \"vendorAddress\": {\"type\": \"string\"}, \"vendorContact\": {\"type\": \"string\"}, \"vendorEmail\": {\"type\": \"string\"}, \"vendorPhone\": {\"type\": \"string\"}, \"shipToName\": {\"type\": \"string\"}, \"shipToAddress\": {\"type\": \"string\"}, \"shipToAttention\": {\"type\": \"string\"}, \"billToName\": {\"type\": \"string\"}, \"billToAddress\": {\"type\": \"string\"}, \"lineItemsList\": {\"type\": \"string\"}, \"lineItemCount\": {\"type\": \"number\"}, \"subtotal\": {\"type\": \"number\"}, \"shippingCost\": {\"type\": \"number\"}, \"tax\": {\"type\": \"number\"}, \"grandTotal\": {\"type\": \"number\"}, \"paymentTerms\": {\"type\": \"string\"}, \"shippingMethod\": {\"type\": \"string\"}, \"notes\": {\"type\": \"string\"}}, \"additionalProperties\": false}",
"binaryPropertyName": "attachment_0"
},
"id": "pdfvector-extract",
"name": "PDF Vector - Extract PO",
"type": "n8n-nodes-pdfvector.pdfVector",
"typeVersion": 2,
"position": [
480,
300
],
"credentials": {
"pdfVectorApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const po = ($input.first().json?.data || $input.first().json) || {};\nconst trackingId = `PO-${Date.now().toString(36).toUpperCase()}`;\nconst grandTotal = parseFloat(po.grandTotal) || 0;\nconst subtotal = parseFloat(po.subtotal) || 0;\nconst grandTotalFormatted = grandTotal.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2});\n\nlet approvalLevel = 'Auto-Approve';\nif (grandTotal >= 25000) approvalLevel = 'VP/CFO Approval';\nelse if (grandTotal >= 5000) approvalLevel = 'Director Approval';\nelse if (grandTotal >= 1000) approvalLevel = 'Manager Approval';\n\nlet urgency = 'Normal'; let daysUntilRequired = null;\nif (po.requiredDate) {\n const req = new Date(po.requiredDate); const today = new Date();\n daysUntilRequired = Math.ceil((req - today) / (1000*60*60*24));\n if (daysUntilRequired <= 3) urgency = 'Urgent';\n else if (daysUntilRequired <= 7) urgency = 'High';\n}\n\nreturn [{ json: {\n trackingId,\n poNumber: po.poNumber || 'N/A',\n vendorName: po.vendorName || 'N/A',\n orderDate: po.orderDate || 'N/A',\n requiredDate: po.requiredDate || 'N/A',\n lineItemCount: parseInt(po.lineItemCount) || 0,\n lineItemsList: po.lineItemsList || 'N/A',\n subtotal, grandTotal, grandTotalFormatted,\n shippingCost: parseFloat(po.shippingCost) || 0,\n tax: parseFloat(po.tax) || 0,\n approvalLevel, urgency, daysUntilRequired,\n paymentTerms: po.paymentTerms || 'N/A',\n processedAt: new Date().toISOString()\n}}];"
},
"id": "process-po",
"name": "Process PO",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "list"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Tracking ID": "={{ $json.trackingId }}",
"PO Number": "={{ $json.poNumber }}",
"Vendor": "={{ $json.vendorName }}",
"Order Date": "={{ $json.orderDate || 'N/A' }}",
"Required Date": "={{ $json.requiredDate || 'N/A' }}",
"Line Items": "={{ $json.lineItemCount }}",
"Subtotal": "={{ $json.subtotal }}",
"Shipping": "={{ $json.shippingCost || 0 }}",
"Tax": "={{ $json.tax || 0 }}",
"Grand Total": "={{ $json.grandTotal }}",
"Approval Level": "={{ $json.approvalLevel }}",
"Urgency": "={{ $json.urgency }}",
"Status": "=Pending Approval",
"Received Date": "={{ $json.processedAt.split('T')[0] }}"
},
"matchingColumns": []
},
"options": {}
},
"id": "sheets-log",
"name": "Log to PO Tracker",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
880,
300
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"authentication": "oAuth2",
"select": "channel",
"channelId": {
"__rl": true,
"value": "YOUR_SLACK_CHANNEL_ID",
"mode": "list"
},
"text": "=\ud83d\udce6 *New Purchase Order Received*\n\n*Tracking:* {{ $('Process PO').item.json.trackingId }}\n*PO Number:* {{ $('Process PO').item.json.poNumber }}\n*Vendor:* {{ $('Process PO').item.json.vendorName }}\n\n\ud83d\udccb *Line Items ({{ $('Process PO').item.json.lineItemCount }}):*\n{{ $('Process PO').item.json.lineItemsList }}\n\n\ud83d\udcb0 *Total:* ${{ $('Process PO').item.json.grandTotalFormatted }}\n\ud83d\udcc5 *Required By:* {{ $('Process PO').item.json.requiredDate }}\n\n\ud83d\udd10 *Approval Required:* {{ $('Process PO').item.json.approvalLevel }}\n\u26a1 *Urgency:* {{ $('Process PO').item.json.urgency }}",
"otherOptions": {}
},
"id": "slack-notify",
"name": "Notify Procurement",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1080,
300
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Gmail Trigger": {
"main": [
[
{
"node": "Get a message",
"type": "main",
"index": 0
}
]
]
},
"Get a message": {
"main": [
[
{
"node": "PDF Vector - Extract PO",
"type": "main",
"index": 0
}
]
]
},
"PDF Vector - Extract PO": {
"main": [
[
{
"node": "Process PO",
"type": "main",
"index": 0
}
]
]
},
"Process PO": {
"main": [
[
{
"node": "Log to PO Tracker",
"type": "main",
"index": 0
}
]
]
},
"Log to PO Tracker": {
"main": [
[
{
"node": "Notify Procurement",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "PDF Vector"
},
{
"name": "Procurement"
},
{
"name": "Finance"
}
],
"meta": {
"templateCredsSetupCompleted": false
}
}
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.
gmailOAuth2googleSheetsOAuth2ApipdfVectorApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
W14 - Purchase Order Processor & Approval Workflow. Uses gmailTrigger, gmail, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 9 nodes.
Source: https://github.com/khanhduyvt0101/workflows/blob/main/n8n-workflows/purchase-order-processor.json — 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.
13. Insurance Pre-Authorization. Uses gmailTrigger, gmail, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 12 nodes.
Job Application Processor & Candidate Scorer. Uses gmailTrigger, gmail, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 10 nodes.
Shipping Document Processor. Uses gmailTrigger, gmail, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 10 nodes.
Insurance Claim Document Processor. Uses gmailTrigger, gmail, n8n-nodes-pdfvector, googleSheets. Event-driven trigger; 9 nodes.
Bank Statement Analyzer & Budget Tracker. Uses stickyNote, gmailTrigger, gmail, n8n-nodes-pdfvector. Event-driven trigger; 8 nodes.