This workflow corresponds to n8n.io template #18196 — 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 →
{
"id": "YMrCBdeNds4rYrdo",
"name": "Review contract risks and route approvals with Google Drive, OpenAI and Gmail",
"tags": [],
"nodes": [
{
"id": "de257bb5-54c0-4e0c-977a-3e213031d727",
"name": "Contract Intake Trigger",
"type": "n8n-nodes-base.googleDriveTrigger",
"position": [
928,
224
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1hcVTxBRUIKA5TzqrjORJspMB0CDqayJ6",
"cachedResultUrl": "https://drive.google.com/drive/folders/1hcVTxBRUIKA5TzqrjORJspMB0CDqayJ6",
"cachedResultName": "AI contract review"
}
},
"typeVersion": 1
},
{
"id": "25b55e33-9960-496c-8ed6-5da8b2f27cab",
"name": "Normalize File Metadata",
"type": "n8n-nodes-base.set",
"position": [
1232,
224
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "519de011-f051-4a44-8c1b-ab1bf6a54662",
"name": "fileId",
"type": "string",
"value": "={{$json.id}}"
},
{
"id": "e8cd4463-4283-4fb1-8383-3c1ac58b747a",
"name": "fileName",
"type": "string",
"value": "={{$json.name}}"
},
{
"id": "814631b1-d7d0-41d4-8724-eb539f204ee0",
"name": "mimeType",
"type": "string",
"value": "={{$json.mimeType}}"
},
{
"id": "b6de0caf-b372-4974-9dac-2f080d875f31",
"name": "fileSize",
"type": "string",
"value": "={{$json.size}}"
},
{
"id": "070a0882-8436-4435-886a-f5f2c286f3ce",
"name": "webViewLink",
"type": "string",
"value": "={{$json.webViewLink}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b2a338cc-3b4c-4fc5-94d3-c0e6354209e8",
"name": "Validate PDF Input",
"type": "n8n-nodes-base.if",
"position": [
1488,
224
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "a6caaad8-9ce2-4e8c-abfb-c3643ac43304",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.mimeType }}",
"rightValue": "application/pdf"
},
{
"id": "c622fc81-fb31-4750-a6b1-211155c0bf11",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.fileId }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "8868ed22-e0cd-4d6c-a786-37e902fe89ed",
"name": "Download Contract PDF",
"type": "n8n-nodes-base.googleDrive",
"position": [
1744,
208
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.fileId }}"
},
"options": {},
"operation": "download"
},
"typeVersion": 3
},
{
"id": "1f7782fa-06b4-4e1b-b4a8-d3f134406851",
"name": "Extract Contract Text",
"type": "n8n-nodes-base.extractFromFile",
"position": [
2000,
208
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1.1
},
{
"id": "da723abc-1825-4501-870d-9ccb1ef2f31f",
"name": "Extract Contract Clauses",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
2336,
208
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {
"store": true,
"temperature": 0
},
"simplify": "={{ true }}",
"responses": {
"values": [
{
"role": "system",
"content": "=You are an expert contract information extraction engine.\n\nYour task is to extract factual information from the contract.\n\nReturn ONLY valid JSON.\n\nDo not include markdown, code fences, explanations, comments, or extra text.\n\nRules:\n\n- Extract only information explicitly present in the contract.\n- Never guess.\n- Never infer information that is not explicitly stated.\n- Return every field.\n- If a scalar value is not found, return null.\n- If a boolean cannot be confirmed, return false.\n- If an array field is not found, return [].\n- Return numbers without currency symbols or commas.\n- Convert warranty periods into days.\n- Convert payment percentages into numbers.\n- Convert payment due periods into calendar days.\n- Extract the liability cap exactly as written.\n- Summary must be a maximum of three sentences.\nvendor_owns_custom_software is true ONLY if the contract explicitly states that the vendor retains ownership of the custom-developed software or custom source code created specifically for this project.\n\n-Do NOT set it to true if the vendor only retains ownership of pre-existing libraries, frameworks, reusable components, methodologies, templates, or internal tools.\n-Return the complete liability limitation sentence exactly as written.\nDo not shorten or paraphrase it.\n\nReturn exactly this JSON structure:\n\n{\n \"parties\": {\n \"client\": null,\n \"vendor\": null\n },\n \"client_name\": null,\n \"vendor_name\": null,\n \"contract_value\": null,\n \"currency\": null,\n \"contract_type\": null,\n \"payment_terms\": {\n \"initial_payment\": null,\n \"mid_payment\": null,\n \"final_payment\": null,\n \"payment_due\": null\n },\n \"payment_terms_net_days\": null,\n \"upfront_payment_percent\": null,\n \"confidentiality_present\": false,\n \"ip_ownership_present\": false,\n \"warranty_days\": null,\n \"liability_cap\": null,\n \"termination_rights_present\": false,\n \"governing_law\": null,\n \"data_security_present\": false,\n \"data_privacy_present\": false,\n \"sla_present\": false,\n \"subcontracting_restriction_present\": false,\n \"customer_data_access\": false,\n \"international_vendor\": false,\n \"ai_or_cloud_services\": false,\n \"automatic_renewal_months\": null,\n \"vendor_owns_custom_software\": false,\n \"unlimited_vendor_liability\": false,\n \"indemnification_vendor_favored\": false,\n \"exclusivity_clause\": false,\n \"non_compete_clause\": false,\n \"summary\": \"\"\n}\n\nExtraction Notes:\n\n- If the contract contains a Data Protection clause covering security safeguards, set data_security_present = true.\n- If the contract contains a Data Protection clause mentioning privacy regulations or privacy compliance, set data_privacy_present = true.\n- If the contract mentions AI development, AI implementation, AI integration, machine learning, generative AI, LLMs, workflow automation using AI, or cloud-hosted software, set ai_or_cloud_services = true.\n- If the contract involves processing, storing, accessing, transmitting, or protecting customer, client, user, personal, confidential, or business data, set customer_data_access = true.\n- If the vendor's registered country differs from the client's country, set international_vendor = true\nExtraction Rules\n\nvendor_owns_custom_software\n\nSet to true ONLY if the contract explicitly states that the vendor retains ownership of the custom-developed software or custom source code created specifically for this project.\n\nDo NOT set it to true if the vendor only retains ownership of:\n\n- Existing libraries\n- Frameworks\n- Reusable components\n- Accelerators\n- Templates\n- Methodologies\n- Internal tools\n\n------------------------------------------------\n\nLiability Cap\n\nReturn the complete liability limitation sentence exactly as written.\n\n------------------------------------------------\n\nGoverning Law\n\nReturn only the governing jurisdiction.\n\nExamples\n\n\"The laws of the State of California, USA\"\n\n\u2193\n\nCalifornia\n\n------------------------------------------------\n\nPayment Due\n\nConvert payment due periods into integer calendar days.\n\n\"within fifteen (15) calendar days\"\n\n\u2193\n\n15\n"
},
{
"content": "=Analyze the following contract and extract the required information.\n\n{{$json.text}}"
},
{
"content": "=Analyze this contract.\n\n{{$json.text}}"
}
]
},
"builtInTools": {}
},
"typeVersion": 2.3
},
{
"id": "28fecce1-fdec-4a83-8940-fb6dfcc66c3b",
"name": "Derive Approval Level",
"type": "n8n-nodes-base.switch",
"position": [
3088,
192
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "LE 25k",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8f92258e-25c4-4b2a-82fe-a3e2cc29c245",
"operator": {
"type": "number",
"operation": "lte"
},
"leftValue": "={{ $json.contract_value }}",
"rightValue": 25000
}
]
},
"renameOutput": true
},
{
"outputKey": "GE 50k",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "63ccdd11-db1a-4c8a-b146-b30c18942eb6",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.contract_value }}",
"rightValue": 50000
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra",
"renameFallbackOutput": "between 25k to 50k"
}
},
"typeVersion": 3.4
},
{
"id": "ffdb159c-5d81-48f4-8872-81ee486d6ee1",
"name": "Legal Approval Email",
"type": "n8n-nodes-base.gmail",
"position": [
3472,
80
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<!DOCTYPE html> <html> <body style=\"margin:0;padding:0;background:#f3f4f6;font-family:Inter,Arial,sans-serif;color:#111827;\"> <div style=\"max-width:760px;margin:0 auto;padding:32px 16px;\"> <div style=\"background:#ffffff;border:1px solid #e5e7eb;border-radius:18px;overflow:hidden;box-shadow:0 10px 30px rgba(15,23,42,0.08);\"> <div style=\"padding:28px 30px;background:linear-gradient(135deg,#0f172a 0%,#1d4ed8 100%);color:#ffffff;\"> <div style=\"font-size:12px;letter-spacing:1.6px;text-transform:uppercase;opacity:0.85;margin-bottom:10px;\"> Contract Review Alert </div> <div style=\"font-size:26px;font-weight:800;line-height:1.2;\"> Approval Needed </div> <div style=\"margin-top:10px;font-size:14px;opacity:0.92;line-height:1.6;\"> A contract has been analyzed and is ready for your review. </div> </div> <div style=\"padding:28px 30px;\"> <div style=\"display:flex;flex-wrap:wrap;gap:14px;margin-bottom:26px;\"> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Risk Score</div> <div style=\"margin-top:8px;font-size:20px;font-weight:800;color:#dc2626;\">{{ $json.risk_score }}</div> </div> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Approval Route</div> <div style=\"margin-top:8px;font-size:18px;font-weight:800;color:#111827;\">{{ $json.approval_route }}</div> </div> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Contract Value</div> <div style=\"margin-top:8px;font-size:18px;font-weight:800;color:#111827;\">{{ $json.currency }} {{ $json.contract_value }}</div> </div> </div> <div style=\"margin-bottom:22px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Contract Details</div> <table style=\"width:100%;border-collapse:collapse;background:#ffffff;border:1px solid #e5e7eb;border-radius:14px;overflow:hidden;\"> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;width:34%;border-bottom:1px solid #e5e7eb;\">Client</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.client_name }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;border-bottom:1px solid #e5e7eb;\">Vendor</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.vendor_name }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;border-bottom:1px solid #e5e7eb;\">Contract Type</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.contract_type }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;\">Governing Law</td> <td style=\"padding:12px 16px;font-weight:600;\">{{ $json.governing_law }}</td> </tr> </table> </div> <div style=\"margin-bottom:22px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Summary</div> <div style=\"background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;line-height:1.7;color:#374151;\"> {{ $json.summary }} </div> </div> <div style=\"display:flex;flex-wrap:wrap;gap:14px;\"> <div style=\"flex:1;min-width:280px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Key Risk Flags</div> <div style=\"background:#fff7ed;border:1px solid #fed7aa;border-radius:14px;padding:16px;\"> <ul style=\"margin:0;padding-left:20px;line-height:1.8;color:#9a3412;\"> {{ $json.risk_flags.map(flag => `<li>${flag}</li>`).join('') }} </ul> </div> </div> <div style=\"flex:1;min-width:280px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Missing Required Clauses</div> <div style=\"background:#fef2f2;border:1px solid #fecaca;border-radius:14px;padding:16px;\"> <ul style=\"margin:0;padding-left:20px;line-height:1.8;color:#b91c1c;\"> {{ $json.missing_required_clauses.length ? $json.missing_required_clauses.map(clause => `<li>${clause}</li>`).join('') : '<li>None</li>' }} </ul> </div> </div> </div> <div style=\"margin-top:24px;padding:16px 18px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:14px;color:#1d4ed8;line-height:1.7;\"> Please review this contract and choose <strong>Approve</strong> or <strong>Decline</strong> to continue the workflow. </div> </div> </div> <div style=\"text-align:center;font-size:12px;color:#94a3b8;margin-top:14px;\"> Contract Review Automation </div> </div> </body> </html>",
"options": {},
"subject": "=Contract review required:{{ $json.parties.client }} X {{ $json.parties.vendor }}",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"buttonDisapprovalStyle": "primary"
}
}
},
"typeVersion": 2.2
},
{
"id": "954accf0-9261-4757-8fbd-7328a3b2a105",
"name": "Finance Approval Email",
"type": "n8n-nodes-base.gmail",
"position": [
3472,
256
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<!DOCTYPE html> <html> <body style=\"margin:0;padding:0;background:#f3f4f6;font-family:Inter,Arial,sans-serif;color:#111827;\"> <div style=\"max-width:760px;margin:0 auto;padding:32px 16px;\"> <div style=\"background:#ffffff;border:1px solid #e5e7eb;border-radius:18px;overflow:hidden;box-shadow:0 10px 30px rgba(15,23,42,0.08);\"> <div style=\"padding:28px 30px;background:linear-gradient(135deg,#0f172a 0%,#1d4ed8 100%);color:#ffffff;\"> <div style=\"font-size:12px;letter-spacing:1.6px;text-transform:uppercase;opacity:0.85;margin-bottom:10px;\"> Contract Review Alert </div> <div style=\"font-size:26px;font-weight:800;line-height:1.2;\"> Approval Needed </div> <div style=\"margin-top:10px;font-size:14px;opacity:0.92;line-height:1.6;\"> A contract has been analyzed and is ready for your review. </div> </div> <div style=\"padding:28px 30px;\"> <div style=\"display:flex;flex-wrap:wrap;gap:14px;margin-bottom:26px;\"> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Risk Score</div> <div style=\"margin-top:8px;font-size:20px;font-weight:800;color:#dc2626;\">{{ $json.risk_score }}</div> </div> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Approval Route</div> <div style=\"margin-top:8px;font-size:18px;font-weight:800;color:#111827;\">{{ $json.approval_route }}</div> </div> <div style=\"flex:1;min-width:180px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;\"> <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:1px;color:#6b7280;\">Contract Value</div> <div style=\"margin-top:8px;font-size:18px;font-weight:800;color:#111827;\">{{ $json.currency }} {{ $json.contract_value }}</div> </div> </div> <div style=\"margin-bottom:22px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Contract Details</div> <table style=\"width:100%;border-collapse:collapse;background:#ffffff;border:1px solid #e5e7eb;border-radius:14px;overflow:hidden;\"> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;width:34%;border-bottom:1px solid #e5e7eb;\">Client</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.client_name }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;border-bottom:1px solid #e5e7eb;\">Vendor</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.vendor_name }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;border-bottom:1px solid #e5e7eb;\">Contract Type</td> <td style=\"padding:12px 16px;border-bottom:1px solid #e5e7eb;font-weight:600;\">{{ $json.contract_type }}</td> </tr> <tr> <td style=\"padding:12px 16px;background:#f9fafb;color:#6b7280;\">Governing Law</td> <td style=\"padding:12px 16px;font-weight:600;\">{{ $json.governing_law }}</td> </tr> </table> </div> <div style=\"margin-bottom:22px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Summary</div> <div style=\"background:#f8fafc;border:1px solid #e5e7eb;border-radius:14px;padding:16px;line-height:1.7;color:#374151;\"> {{ $json.summary }} </div> </div> <div style=\"display:flex;flex-wrap:wrap;gap:14px;\"> <div style=\"flex:1;min-width:280px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Key Risk Flags</div> <div style=\"background:#fff7ed;border:1px solid #fed7aa;border-radius:14px;padding:16px;\"> <ul style=\"margin:0;padding-left:20px;line-height:1.8;color:#9a3412;\"> {{ $json.risk_flags.map(flag => `<li>${flag}</li>`).join('') }} </ul> </div> </div> <div style=\"flex:1;min-width:280px;\"> <div style=\"font-size:18px;font-weight:800;margin-bottom:12px;\">Missing Required Clauses</div> <div style=\"background:#fef2f2;border:1px solid #fecaca;border-radius:14px;padding:16px;\"> <ul style=\"margin:0;padding-left:20px;line-height:1.8;color:#b91c1c;\"> {{ $json.missing_required_clauses.length ? $json.missing_required_clauses.map(clause => `<li>${clause}</li>`).join('') : '<li>None</li>' }} </ul> </div> </div> </div> <div style=\"margin-top:24px;padding:16px 18px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:14px;color:#1d4ed8;line-height:1.7;\"> Please review this contract and choose <strong>Approve</strong> or <strong>Decline</strong> to continue the workflow. </div> </div> </div> <div style=\"text-align:center;font-size:12px;color:#94a3b8;margin-top:14px;\"> Contract Review Automation </div> </div> </body> </html>",
"options": {},
"subject": "=Contract review required:{{ $json.parties.client }} X {{ $json.parties.vendor }}",
"operation": "sendAndWait"
},
"typeVersion": 2.2
},
{
"id": "c44338b2-d58c-4a1b-99bf-9c30b2a986e0",
"name": "Manager Approval Email",
"type": "n8n-nodes-base.gmail",
"position": [
3472,
448
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>Contract Review Report</title>\n</head>\n\n<body style=\"margin:0;padding:0;background:#f4f7fb;font-family:Arial,Helvetica,sans-serif;\">\n\n<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f4f7fb;padding:40px 0;\">\n<tr>\n<td align=\"center\">\n\n<table width=\"700\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#ffffff;border-radius:12px;overflow:hidden;border:1px solid #e5e7eb;\">\n\n<tr>\n<td style=\"background:#1f4e79;color:#ffffff;padding:24px 30px;\">\n<h2 style=\"margin:0;\">Contract Policy Review Report</h2>\n<p style=\"margin:8px 0 0;font-size:14px;opacity:0.9;\">\nAutomated Contract Compliance Analysis\n</p>\n</td>\n</tr>\n\n<tr>\n<td style=\"padding:30px;\">\n\n<h3 style=\"margin-top:0;color:#1f2937;\">Contract Summary</h3>\n\n<table width=\"100%\" cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse:collapse;\">\n\n<tr>\n<td style=\"font-weight:bold;width:220px;\">Client</td>\n<td>{{$json.client_name}}</td>\n</tr>\n\n<tr style=\"background:#f8fafc;\">\n<td style=\"font-weight:bold;\">Vendor</td>\n<td>{{$json.vendor_name}}</td>\n</tr>\n\n<tr>\n<td style=\"font-weight:bold;\">Contract Value</td>\n<td>{{$json.currency}} {{$json.contract_value}}</td>\n</tr>\n\n<tr style=\"background:#f8fafc;\">\n<td style=\"font-weight:bold;\">Contract Type</td>\n<td>{{$json.contract_type}}</td>\n</tr>\n\n<tr>\n<td style=\"font-weight:bold;\">Governing Law</td>\n<td>{{$json.governing_law}}</td>\n</tr>\n\n<tr style=\"background:#f8fafc;\">\n<td style=\"font-weight:bold;\">Risk Score</td>\n<td>\n<span style=\"background:#dc2626;color:white;padding:6px 14px;border-radius:20px;font-weight:bold;\">\n{{$json.risk_score}}\n</span>\n</td>\n</tr>\n\n<tr>\n<td style=\"font-weight:bold;\">Approval Route</td>\n<td>{{ $json.approval_route.join(\", \") }}</td>\n</tr>\n\n</table>\n\n<hr style=\"margin:30px 0;border:none;border-top:1px solid #e5e7eb;\">\n\n<h3 style=\"color:#1f2937;\">Executive Summary</h3>\n\n<div style=\"background:#f8fafc;padding:18px;border-left:5px solid #2563eb;border-radius:6px;\">\n{{$json.summary}}\n</div>\n\n<hr style=\"margin:30px 0;border:none;border-top:1px solid #e5e7eb;\">\n\n<h3 style=\"color:#1f2937;\">Policy Risks</h3>\n\n<div style=\"background:#fff8f8;border:1px solid #fecaca;border-radius:8px;padding:15px;\">\n\n{{ $json.risk_flags.length\n? \"<ul><li>\" + $json.risk_flags.join(\"</li><li>\") + \"</li></ul>\"\n: \"<p>No policy risks identified.</p>\"\n}}\n\n</div>\n\n<hr style=\"margin:30px 0;border:none;border-top:1px solid #e5e7eb;\">\n\n<h3 style=\"color:#1f2937;\">Missing Required Clauses</h3>\n\n<div style=\"background:#fffbea;border:1px solid #fde68a;border-radius:8px;padding:15px;\">\n\n{{ $json.missing_required_clauses.length\n? \"<ul><li>\" + $json.missing_required_clauses.join(\"</li><li>\") + \"</li></ul>\"\n: \"<p>All mandatory clauses are present.</p>\"\n}}\n\n</div>\n\n<hr style=\"margin:30px 0;border:none;border-top:1px solid #e5e7eb;\">\n\n<h3 style=\"color:#1f2937;\">Key Contract Information</h3>\n\n<table width=\"100%\" cellpadding=\"10\" cellspacing=\"0\" style=\"border-collapse:collapse;\">\n\n<tr style=\"background:#f8fafc;\">\n<td><strong>Initial Payment</strong></td>\n<td>{{$json.payment_terms.initial_payment}}%</td>\n</tr>\n\n<tr>\n<td><strong>Mid Payment</strong></td>\n<td>{{$json.payment_terms.mid_payment}}%</td>\n</tr>\n\n<tr style=\"background:#f8fafc;\">\n<td><strong>Final Payment</strong></td>\n<td>{{$json.payment_terms.final_payment}}%</td>\n</tr>\n\n<tr>\n<td><strong>Warranty</strong></td>\n<td>{{$json.warranty_days}} Days</td>\n</tr>\n\n<tr style=\"background:#f8fafc;\">\n<td><strong>Liability Cap</strong></td>\n<td>{{$json.liability_cap}}</td>\n</tr>\n\n</table>\n\n</td>\n</tr>\n\n<tr>\n<td style=\"background:#f3f4f6;padding:20px;text-align:center;font-size:13px;color:#6b7280;\">\n\nThis report was automatically generated by the AI Contract Review System.\n\n</td>\n</tr>\n\n</table>\n\n</td>\n</tr>\n</table>\n\n</body>\n</html>",
"options": {},
"subject": "=Contract review required:{{ $json.parties.client }} X {{ $json.parties.vendor }}",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"buttonDisapprovalStyle": "primary"
}
}
},
"typeVersion": 2.2
},
{
"id": "dad3c3b7-f0d7-4499-a517-d72ce5ecb2bd",
"name": "Check Approval Decision",
"type": "n8n-nodes-base.if",
"position": [
3776,
224
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e454cbf4-6fa6-4553-8ec0-73875782ed85",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.3
},
{
"id": "cc44b6a4-b2a8-4ffd-92ed-f31766068e93",
"name": "Log Approved Contract",
"type": "n8n-nodes-base.googleSheets",
"position": [
4048,
80
],
"parameters": {
"columns": {
"value": {
"decision\n": "APPROVED",
"file_name": "={{ $('Normalize File Metadata').item.json.fileName }}",
"contract_id": "={{ $('Normalize File Metadata').item.json.fileId }}",
"risk_score\n": "={{ $('Company Policy Engine').item.json.risk_score }}",
"vendor_name": "={{ $('Company Policy Engine').item.json.vendor_name }}",
"client_name\n": "={{ $('Company Policy Engine').item.json.client_name }}",
"contract_value": "={{ $('Company Policy Engine').item.json.contract_value }}"
},
"schema": [
{
"id": "contract_id",
"type": "string",
"display": true,
"required": false,
"displayName": "contract_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "file_name",
"type": "string",
"display": true,
"required": false,
"displayName": "file_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "client_name\n",
"type": "string",
"display": true,
"required": false,
"displayName": "client_name\n",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "vendor_name",
"type": "string",
"display": true,
"required": false,
"displayName": "vendor_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "contract_value",
"type": "string",
"display": true,
"required": false,
"displayName": "contract_value",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "risk_score\n",
"type": "string",
"display": true,
"required": false,
"displayName": "risk_score\n",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "decision\n",
"type": "string",
"display": true,
"required": false,
"displayName": "decision\n",
"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/1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw/edit?usp=drivesdk",
"cachedResultName": "Untitled spreadsheet"
}
},
"typeVersion": 4.7
},
{
"id": "dfd0400e-2e99-415a-9ae5-0ab370682c16",
"name": "Log Rejected Contract",
"type": "n8n-nodes-base.googleSheets",
"position": [
4064,
368
],
"parameters": {
"columns": {
"value": {
"file_name": "={{ $('Normalize File Metadata').item.json.fileName }}",
"contract_id": "={{ $('Validate PDF Input').item.json.fileId }}",
"risk_score\n": "={{ $('Company Policy Engine').item.json.risk_score }}",
"vendor_name": "={{ $('Company Policy Engine').item.json.vendor_name }}",
"client_name\n": "={{ $('Company Policy Engine').item.json.client_name }}",
"contract_value": "={{ $('Company Policy Engine').item.json.contract_value }}"
},
"schema": [
{
"id": "contract_id",
"type": "string",
"display": true,
"required": false,
"displayName": "contract_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "file_name",
"type": "string",
"display": true,
"required": false,
"displayName": "file_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "client_name\n",
"type": "string",
"display": true,
"required": false,
"displayName": "client_name\n",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "vendor_name",
"type": "string",
"display": true,
"required": false,
"displayName": "vendor_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "contract_value",
"type": "string",
"display": true,
"required": false,
"displayName": "contract_value",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "risk_score\n",
"type": "string",
"display": true,
"required": false,
"displayName": "risk_score\n",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "decision\n",
"type": "string",
"display": true,
"required": false,
"displayName": "decision\n",
"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/1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1z3e3rP66M3aMHzhFTnopIS8_9U1aFXdhi939NshL2dw/edit?usp=drivesdk",
"cachedResultName": "Untitled spreadsheet"
}
},
"typeVersion": 4.7
},
{
"id": "e2e2bdf7-7587-4b3b-af3d-94435b381f41",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
64
],
"parameters": {
"color": "#FFFFFF",
"width": 1392,
"height": 336,
"content": "**Intake and extraction**\nThis group watches the Drive folder, validates that the incoming file is a PDF, downloads the binary contract, extracts the text, and normalizes the text for downstream AI analysis. It prepares a clean contractText payload and preserves file metadata for tracking."
},
"typeVersion": 1
},
{
"id": "d212cc02-e02d-4f43-baef-c131d5b917aa",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
3328,
-176
],
"parameters": {
"color": "#FFFFFF",
"width": 960,
"height": 832,
"content": "## Routing ,approval and Logging\n\nThis group routes the contract to the correct reviewer, waits for the approval or decline decision, and then logs the final outcome in Google Sheets. It serves as the full approval and audit trail stage of the workflow.\n\n"
},
"typeVersion": 1
},
{
"id": "a2218d8e-3b60-4599-aaf9-42b6b2ca0065",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2304,
48
],
"parameters": {
"color": "#FFFFFF",
"width": 992,
"height": 400,
"content": "## AI analysis and policy comparison\nThis group sends the cleaned contract text to OpenAI, parses the structured JSON response, compares the extracted clauses against company policy, and computes the final risk score and approval level. This is where missing clauses, policy violations, and approval routing are determined.\n\n"
},
"typeVersion": 1
},
{
"id": "7aa5eb26-42e1-466f-85d0-89a6193f530d",
"name": "Company Policy Engine",
"type": "n8n-nodes-base.code",
"position": [
2880,
208
],
"parameters": {
"jsCode": "const data = { ...$json };\n\nconst missing = [];\nconst riskFlags = [];\nconst approval = [];\n\nlet riskScore = \"Low\";\n\nconst severity = {\n Low: 1,\n Medium: 2,\n High: 3,\n Critical: 4,\n};\n\nfunction raise(level) {\n if (severity[level] > severity[riskScore]) {\n riskScore = level;\n }\n}\n\n// -------------------------\n// Missing Required Clauses\n// -------------------------\n\nif (!data.confidentiality_present) {\n missing.push(\"Confidentiality\");\n riskFlags.push(\"Missing confidentiality clause\");\n raise(\"Critical\");\n}\n\nif (!data.ip_ownership_present) {\n missing.push(\"IP Ownership\");\n riskFlags.push(\"Missing IP ownership clause\");\n raise(\"Critical\");\n}\n\nif (!data.termination_rights_present) {\n missing.push(\"Termination Rights\");\n riskFlags.push(\"Missing termination rights clause\");\n raise(\"High\");\n}\n\nif (!data.data_security_present) {\n missing.push(\"Data Security\");\n riskFlags.push(\"Missing data security clause\");\n raise(\"High\");\n}\n\nif (!data.data_privacy_present) {\n missing.push(\"Data Privacy\");\n riskFlags.push(\"Missing data privacy clause\");\n raise(\"High\");\n}\n\nif (!data.sla_present) {\n missing.push(\"SLA\");\n riskFlags.push(\"Missing SLA\");\n raise(\"Medium\");\n}\n\nif (!data.subcontracting_restriction_present) {\n missing.push(\"Subcontracting Restriction\");\n}\n\n// -------------------------\n// Approval Matrix\n// -------------------------\n\nconst value = data.contract_value || 0;\n\nif (value <= 25000) {\n approval.push(\"Department Manager\");\n} else if (value <= 50000) {\n approval.push(\"Legal\");\n} else {\n approval.push(\"Legal\", \"Finance\");\n}\n\nif (data.customer_data_access) {\n approval.push(\"Security\");\n}\n\nif (data.ai_or_cloud_services) {\n approval.push(\"Security\");\n}\n\nif (data.international_vendor) {\n approval.push(\"Procurement\");\n}\n\n// -------------------------\n// Business Rules\n// -------------------------\n\nif (\n data.upfront_payment_percent !== null &&\n data.upfront_payment_percent > 20\n) {\n riskFlags.push(\"Upfront payment exceeds 20%\");\n raise(\"Medium\");\n}\n\nif (\n data.payment_terms_net_days !== null &&\n data.payment_terms_net_days > 45\n) {\n riskFlags.push(\"Payment terms exceed Net 45\");\n raise(\"Medium\");\n}\n\nif (\n data.warranty_days !== null &&\n data.warranty_days < 90\n) {\n riskFlags.push(\"Warranty less than 90 days\");\n raise(\"High\");\n}\n\nif (\n data.governing_law &&\n data.governing_law.toLowerCase() !== \"texas\"\n) {\n riskFlags.push(\"Governing law outside Texas\");\n raise(\"Medium\");\n}\n\nif (data.unlimited_vendor_liability) {\n riskFlags.push(\"Unlimited vendor liability\");\n raise(\"High\");\n}\n\nif (data.vendor_owns_custom_software) {\n riskFlags.push(\"Vendor retains ownership of custom software\");\n raise(\"High\");\n}\n\nif (data.indemnification_vendor_favored) {\n riskFlags.push(\"Vendor-favored indemnification\");\n raise(\"High\");\n}\n\nif (data.exclusivity_clause) {\n riskFlags.push(\"Exclusivity clause present\");\n raise(\"Medium\");\n}\n\nif (data.non_compete_clause) {\n riskFlags.push(\"Non-compete clause present\");\n raise(\"Medium\");\n}\n\nif (\n data.automatic_renewal_months !== null &&\n data.automatic_renewal_months > 12\n) {\n riskFlags.push(\"Automatic renewal exceeds 12 months\");\n raise(\"Medium\");\n}\n\n// -------------------------\n\ndata.missing_required_clauses = missing;\ndata.risk_flags = [...new Set(riskFlags)];\ndata.risk_score = riskScore;\ndata.approval_route = [...new Set(approval)];\n\nreturn [\n {\n json: data,\n },\n];"
},
"typeVersion": 2
},
{
"id": "b8b06275-e70f-46a1-8055-77f8518645ee",
"name": "Parse JSON",
"type": "n8n-nodes-base.code",
"position": [
2672,
208
],
"parameters": {
"jsCode": "const raw = $json.output?.[0]?.content?.[0]?.text || \"\";\n\nconst cleaned = raw\n .replace(/^```json/i, \"\")\n .replace(/^```/, \"\")\n .replace(/```$/, \"\")\n .trim();\n\nreturn [\n {\n json: JSON.parse(cleaned)\n }\n];"
},
"typeVersion": 2
},
{
"id": "9bff21b0-d012-44cd-96ba-6ef6645b9bed",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
-176
],
"parameters": {
"width": 592,
"height": 1088,
"content": "# Review Contracts and Route Approvals from Google Drive\n\nThis workflow automates contract review, risk assessment, approval routing, and audit logging. When a contract is uploaded to Google Drive, the workflow extracts document content, analyzes key clauses using AI, evaluates compliance against company policies, and determines the appropriate approval path.\n\nThe workflow helps legal, procurement, finance, and operations teams reduce manual review effort, identify contractual risks earlier, and maintain a complete audit trail of approval decisions.\n\n### Tools & Integrations\n\n- Google Drive\n- OpenAI\n- Gmail\n- Google Sheets\n\n### How it works\n\n1. Monitor Google Drive for newly uploaded contracts.\n2. Validate and extract text from PDF documents.\n3. Analyze key clauses and obligations using AI.\n4. Assess contract risk and policy compliance.\n5. Determine the required approval level.\n6. Route contracts to reviewers via email.\n7. Capture approval decisions.\n8. Log outcomes for compliance and auditing.\n\n### Setup\n\n1. Connect Google Drive, OpenAI, Gmail, and Google Sheets.\n2. Configure reviewer email addresses.\n3. Update policy rules and approval thresholds.\n4. Upload a sample contract and test the workflow.\n\n### Customization\n\nModify approval levels, policy rules, risk thresholds, reviewer groups, and audit fields to match your organization's process."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "fd472ce9-8873-413e-8d1a-9faf77b2e54c",
"nodeGroups": [],
"connections": {
"Parse JSON": {
"main": [
[
{
"node": "Company Policy Engine",
"type": "main",
"index": 0
}
]
]
},
"Validate PDF Input": {
"main": [
[
{
"node": "Download Contract PDF",
"type": "main",
"index": 0
}
]
]
},
"Legal Approval Email": {
"main": [
[
{
"node": "Check Approval Decision",
"type": "main",
"index": 0
}
]
]
},
"Company Policy Engine": {
"main": [
[
{
"node": "Derive Approval Level",
"type": "main",
"index": 0
}
]
]
},
"Derive Approval Level": {
"main": [
[
{
"node": "Legal Approval Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Finance Approval Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Manager Approval Email",
"type": "main",
"index": 0
}
]
]
},
"Download Contract PDF": {
"main": [
[
{
"node": "Extract Contract Text",
"type": "main",
"index": 0
}
]
]
},
"Extract Contract Text": {
"main": [
[
{
"node": "Extract Contract Clauses",
"type": "main",
"index": 0
}
]
]
},
"Finance Approval Email": {
"main": [
[
{
"node": "Check Approval Decision",
"type": "main",
"index": 0
}
]
]
},
"Manager Approval Email": {
"main": [
[
{
"node": "Check Approval Decision",
"type": "main",
"index": 0
}
]
]
},
"Check Approval Decision": {
"main": [
[
{
"node": "Log Approved Contract",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Rejected Contract",
"type": "main",
"index": 0
}
]
]
},
"Contract Intake Trigger": {
"main": [
[
{
"node": "Normalize File Metadata",
"type": "main",
"index": 0
}
]
]
},
"Normalize File Metadata": {
"main": [
[
{
"node": "Validate PDF Input",
"type": "main",
"index": 0
}
]
]
},
"Extract Contract Clauses": {
"main": [
[
{
"node": "Parse JSON",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow monitors a Google Drive folder for new contract PDFs, extracts and analyzes their text with OpenAI, routes the contract for email-based approval via Gmail based on contract value and policy risks, and logs the final decision to Google Sheets. Triggers every minute…
Source: https://n8n.io/workflows/18196/ — 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.
This workflow automates end-to-end contract analysis when a new file is uploaded to Google Drive. It downloads the contract, extracts its content, and uses AI to analyze legal terms, obligations, and
The Problem That it Solves
Content creators, YouTubers, and social media managers who want to repurpose long form videos into short clips without doing it manually. Works on self hosted n8n instances.
AI Expense Tracker. Uses gmailTrigger, openAi, googleDrive, googleSheets. Event-driven trigger; 31 nodes.
An n8n-based automation that generates client proposals from a form, lets you review everything in one place, and sends the proposal only when you approve it.