法律契約データを抽出し、VLM Run、Google Workspace、Slackを使ってリマインド送信
これは自動化ワークフローで、14個のノードを含みます。主にSet, Code, Slack, Webhook, GoogleDriveなどのノードを使用。 法律契約データを抽出し、VLM Run、Google Workspace、Slackを用いてアラートを送信
- •Slack Bot Token または Webhook URL
- •HTTP Webhookエンドポイント(n8nが自動生成)
- •Google Drive API認証情報
- •Google Sheets API認証情報
使用ノード (14)
カテゴリー
{
"meta": {
"instanceId": "96d35e452e0d9a182973416b7532cfc5643239aaaa764a5bf74d52ca84f4a35c",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "bdfebade-893c-411c-80c6-0dace07f7dc9",
"name": "📁 入力処理ドキュメンテーション",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 7,
"width": 400,
"height": 680,
"content": "## 📁 Input Processing\n\n**Monitors & downloads contract files from Google Drive.**\n\n**Process:**\n1. Watches designated Drive folder\n2. Auto-triggers on new uploads\n3. Downloads files for AI processing\n\n**Supported Formats:**\n- Images (JPG, PNG, WEBP)\n- PDF documents\n- Mobile camera uploads\n- Scanned contracts"
},
"typeVersion": 1
},
{
"id": "2fca40fa-ac4a-4515-a1e0-295cdcbfc595",
"name": "契約アップロードの監視",
"type": "n8n-nodes-base.googleDriveTrigger",
"notes": "Monitors Google Drive folder for new receipt uploads and triggers processing automatically.",
"position": [
48,
480
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1S6baavqJn98MjUlbB6KtmARCWuWEekIZ",
"cachedResultUrl": "https://drive.google.com/drive/folders/1S6baavqJn98MjUlbB6KtmARCWuWEekIZ",
"cachedResultName": "test_data"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "zYyIOFMdGz258avn",
"name": "Google Drive account 6"
}
},
"typeVersion": 1
},
{
"id": "95acb226-9205-4a21-9a2d-c9792bc81de4",
"name": "契約ファイルのダウンロード",
"type": "n8n-nodes-base.googleDrive",
"notes": "Downloads receipt files from Google Drive for AI processing.",
"position": [
256,
480
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {
"binaryPropertyName": "data"
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "zYyIOFMdGz258avn",
"name": "Google Drive account 6"
}
},
"typeVersion": 3
},
{
"id": "61fa2c83-72cd-44b0-a5cd-5fbaeef5dfb1",
"name": "🤖 AI抽出ドキュメンテーション",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
0
],
"parameters": {
"width": 416,
"height": 680,
"content": "## 🤖 VLM Run Contract Extraction\n\n**Uses VLM Run node to extract structured data from contract images/PDFs.**\n\n**Extracts:**\n- Contract ID\n- Title\n- Parties\n- Effective Date\n- Termination Date\n\n**Features:**\n- Handles poor quality images\n- Various receipt formats\n- OCR text recognition"
},
"typeVersion": 1
},
{
"id": "84d28c8a-b33c-4bc3-9489-846c3b412d4a",
"name": "VLM Run ContractParser",
"type": "@vlm-run/n8n-nodes-vlmrun.vlmRun",
"position": [
560,
480
],
"parameters": {
"operation": "executeAgent",
"agentPrompt": "extract data from the invoice or contract, Extract the key details from this lease contract. I am expecting the output to be in JSON format, with tags, using parameters : contract_id, title, parties (with role), property_address, effective_date, termination_date, rent_amount, security_deposit, payment_terms, governing_law . All the parameters should get values from the pdf of data file from the download contract file. \nNormalize dates to YYYY-MM-DD and amounts as numbers with currency. \nIf a field is missing, return null.",
"agentCallbackUrl": "https://playground.attensys.ai/webhook/b905e71d-8ea5-4fc2-a773-b0f92e5398e4"
},
"credentials": {
"vlmRunApi": {
"id": "B7ZYM8AfBgjnOEOl",
"name": "VLM Run account 5"
}
},
"typeVersion": 1
},
{
"id": "17996d92-afea-484c-88d3-9b2b673b1f4c",
"name": "📊 ストレージドキュメンテーション",
"type": "n8n-nodes-base.stickyNote",
"position": [
1056,
0
],
"parameters": {
"color": 7,
"width": 420,
"height": 680,
"content": "## 📊 Data Storage\n\n**Structures and stores extracted data in Google Sheets.**\n\n**Features:**\n- Clean, organized format\n- Centralized expense database\n- Auto-appends new entries\n- Analysis-ready data\n\n**Data Fields:**\n- ID\n- Title\n- Parties\n- Effective and Termination Date\n\n**Benefits:**\n- Real-time tracking\n- Easy exports\n- Mobile access"
},
"typeVersion": 1
},
{
"id": "70c2c9c5-d950-495f-9e91-5a0b402ef739",
"name": "経費データベースへの保存",
"type": "n8n-nodes-base.googleSheets",
"notes": "Automatically saves extracted receipt data to Google Sheets for expense tracking.",
"position": [
1344,
480
],
"parameters": {
"columns": {
"value": {
"Title": "={{$node[\"Format Contract Data\"].json[\"Title\"]}}",
"Parties": "={{$node[\"Format Contract Data\"].json[\"Parties\"]}}",
"Contract ID": "={{$node[\"Format Contract Data\"].json[\"Contract ID\"]}}",
"Effective Date": "={{$node[\"Format Contract Data\"].json[\"Effective Date\"]}}",
"Termination Date": "={{$node[\"Format Contract Data\"].json[\"Termination Date\"]}}"
},
"schema": [
{
"id": "Contract ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Contract ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Parties",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Parties",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Effective Date",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Effective Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Termination Date",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Termination Date",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Customer"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/11_VjMdhv_JN2eSRZiw_t0dIN-yShkn2jlCDwiG8eb14/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1lg0aJKvd7E2pbhumHNjcgxUfEQKvlBs9h1zZbhSeqas",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1lg0aJKvd7E2pbhumHNjcgxUfEQKvlBs9h1zZbhSeqas/edit?usp=drivesdk",
"cachedResultName": "test"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "sdLQgQJjowDNfXMU",
"name": "Google Sheets account 7"
}
},
"typeVersion": 4.6
},
{
"id": "f752ffb1-d4eb-4d69-919d-2f4d72fb753e",
"name": "契約データのフォーマット",
"type": "n8n-nodes-base.set",
"notes": "Transforms AI-extracted receipt data into clean, structured format for spreadsheet storage.",
"position": [
1136,
480
],
"parameters": {
"values": {
"string": [
{
"name": "Contract ID",
"value": "={{ $json.body.response.contract_id }}"
},
{
"name": "Title",
"value": "={{ $json.body.response.title }}"
},
{
"name": "Parties",
"value": "={{ $json.body.parties && $json.body.parties.length ? $json.body.parties.map(p => p.name + \" (\"+ p.role + \")\").join(\"; \") : \"\" }}"
},
{
"name": "Effective Date",
"value": "={{ $json.body.response.effective_date }}"
},
{
"name": "Termination Date",
"value": "={{ $json.body.response.termination_date }}"
}
]
},
"options": {},
"keepOnlySet": true
},
"typeVersion": 1
},
{
"id": "d04b627c-1b80-4692-91a3-2df61bec0b4d",
"name": "メッセージの送信",
"type": "n8n-nodes-base.slack",
"position": [
1712,
512
],
"webhookId": "6b8dcfb9-51a9-418b-8469-4bf5b5894f2a",
"parameters": {
"text": "=*New Contract Processed* 📄\n• Contract ID: {{$node[\"Format Contract Data\"].json[\"Contract ID\"] || \"N/A\"}}\n• Title: {{$node[\"Format Contract Data\"].json[\"Title\"] || \"N/A\"}}\n• Parties: {{$node[\"Format Contract Data\"].json[\"Parties\"] || \"N/A\"}}\n• Effective: {{$node[\"Format Contract Data\"].json[\"Effective Date\"] || \"N/A\"}}\n• Termination: {{$node[\"Format Contract Data\"].json[\"Termination Date\"] || \"N/A\"}}\n🔗 {{$node[\"Format Contract Data\"].json[\"Drive Link\"] || $node[\"Save to Expense Database\"].json[\"driveLink\"] || \"No drive link available\"}}\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C081Z0KL546",
"cachedResultName": "test"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "M00QrTNTmnr6yiTS",
"name": "Slack account 11"
}
},
"typeVersion": 2.3
},
{
"id": "955768a3-5fac-4296-a5a3-d307a98b471c",
"name": "カレンダーイベントの準備",
"type": "n8n-nodes-base.code",
"position": [
1616,
336
],
"parameters": {
"jsCode": "// n8n Function node code\n// Reads from Format Contract Data node and returns 1..3 items, each has .json with summary, description, start, end (YYYY-MM-DD)\n\nconst fmt = $node[\"Format Contract Data\"].json;\nconst title = fmt[\"Title\"] || \"Untitled Contract\";\nconst cid = fmt[\"Contract ID\"] || \"\";\nconst parties = fmt[\"Parties\"] || \"\";\nconst drive = fmt[\"Drive Link\"] || \"\";\n\nfunction isoDate(d) {\n // return YYYY-MM-DD\n return d.toISOString().split('T')[0];\n}\n\nfunction makeAllDayDates(dateStr) {\n // Accepts YYYY-MM-DD (or other parseable), returns start and end for all-day event.\n if(!dateStr) return null;\n const d = new Date(dateStr + \"T00:00:00\");\n const start = isoDate(d);\n const endD = new Date(d);\n endD.setDate(endD.getDate() + 1); // exclusive end for all-day events\n const end = isoDate(endD);\n return { start, end };\n}\n\nconst items = [];\n\n// Effective Date event\nconst eff = makeAllDayDates(fmt[\"Effective Date\"]);\nif (eff) {\n items.push({\n json: {\n summary: `${title} — Effective Date`,\n description: `Contract ID: ${cid}\\nParties: ${parties}\\nDrive: ${drive}`,\n start: eff.start,\n end: eff.end,\n allDay: true,\n metaType: \"effective\"\n }\n });\n}\n\n// Termination Date event\nconst term = makeAllDayDates(fmt[\"Termination Date\"]);\nif (term) {\n items.push({\n json: {\n summary: `${title} — Termination Date`,\n description: `Contract ID: ${cid}\\nParties: ${parties}\\nDrive: ${drive}`,\n start: term.start,\n end: term.end,\n allDay: true,\n metaType: \"termination\"\n }\n });\n\n // Renewal review reminder 60 days before termination\n const termDate = new Date(fmt[\"Termination Date\"] + \"T00:00:00\");\n const reminderDate = new Date(termDate);\n reminderDate.setDate(reminderDate.getDate() - 60); // change 60 to your preferred days\n const remStart = isoDate(reminderDate);\n const remEndD = new Date(reminderDate);\n remEndD.setDate(remEndD.getDate() + 1);\n const remEnd = isoDate(remEndD);\n\n items.push({\n json: {\n summary: `${title} — Renewal Review (Reminder)`,\n description: `Contract ID: ${cid}\\nTermination Date: ${fmt[\"Termination Date\"]}\\nAction: Review & decide renewal.`,\n start: remStart,\n end: remEnd,\n allDay: true,\n metaType: \"renewal_reminder\"\n }\n });\n}\n\nreturn items;\n"
},
"typeVersion": 2
},
{
"id": "f3301d1a-5773-4598-ba4e-71019a4966bd",
"name": "イベントの作成",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1808,
336
],
"parameters": {
"end": "={{$json[\"end\"]}}",
"start": "={{$json[\"start\"]}}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "sayonaraistata@gmail.com",
"cachedResultName": "sayonaraistata@gmail.com"
},
"additionalFields": {
"allday": "yes",
"summary": "={{$json[\"summary\"]}}",
"description": "={{$json[\"description\"]}}"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "9TLut5ZDt3hcaQEo",
"name": "Google Calendar account 3"
}
},
"typeVersion": 1.3
},
{
"id": "dd656271-d2a3-4f8a-9df8-1da0596b2734",
"name": "📊 ストレージドキュメンテーション1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1552,
0
],
"parameters": {
"color": 7,
"width": 420,
"height": 680,
"content": "## 🔔 Notifications Added:\n\n1. **Slack** → Posts contract details & AI-generated summary to #all-n8n-test for team visibility.\n\n2. **Google Calendar** → Auto-creates all-day events:\n • Effective Date\n • Termination Date\n • Renewal Reminder (30 days before)\n → Helps track key contract milestones.\n"
},
"typeVersion": 1
},
{
"id": "99fdd61d-c6a9-4e74-989a-e56b47caf2e9",
"name": "付箋メモ3",
"type": "n8n-nodes-base.stickyNote",
"position": [
368,
704
],
"parameters": {
"color": 5,
"width": 704,
"height": 144,
"content": "## 📝 Set the Callback URL\n\nMake sure to paste the **Production URL** of your n8n Webhook node into the **Callback URL** field in VLM Run. This ensures that the extracted image links are securely and reliably sent back to your live workflow. Do **not** use localhost or development URLs, they won’t be reachable by VLM Run’s servers."
},
"typeVersion": 1
},
{
"id": "6d26e945-a724-4e3b-a8ff-c91dd8500f5f",
"name": "契約の受信",
"type": "n8n-nodes-base.webhook",
"position": [
784,
480
],
"webhookId": "b905e71d-8ea5-4fc2-a773-b0f92e5398e4",
"parameters": {
"path": "b905e71d-8ea5-4fc2-a773-b0f92e5398e4",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
}
],
"pinData": {},
"connections": {
"6d26e945-a724-4e3b-a8ff-c91dd8500f5f": {
"main": [
[
{
"node": "f752ffb1-d4eb-4d69-919d-2f4d72fb753e",
"type": "main",
"index": 0
}
]
]
},
"f752ffb1-d4eb-4d69-919d-2f4d72fb753e": {
"main": [
[
{
"node": "70c2c9c5-d950-495f-9e91-5a0b402ef739",
"type": "main",
"index": 0
}
]
]
},
"95acb226-9205-4a21-9a2d-c9792bc81de4": {
"main": [
[
{
"node": "84d28c8a-b33c-4bc3-9489-846c3b412d4a",
"type": "main",
"index": 0
}
]
]
},
"955768a3-5fac-4296-a5a3-d307a98b471c": {
"main": [
[
{
"node": "f3301d1a-5773-4598-ba4e-71019a4966bd",
"type": "main",
"index": 0
}
]
]
},
"2fca40fa-ac4a-4515-a1e0-295cdcbfc595": {
"main": [
[
{
"node": "95acb226-9205-4a21-9a2d-c9792bc81de4",
"type": "main",
"index": 0
}
]
]
},
"70c2c9c5-d950-495f-9e91-5a0b402ef739": {
"main": [
[
{
"node": "d04b627c-1b80-4692-91a3-2df61bec0b4d",
"type": "main",
"index": 0
},
{
"node": "955768a3-5fac-4296-a5a3-d307a98b471c",
"type": "main",
"index": 0
}
]
]
}
}
}このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
Shahrear
@shahrearI’m Shahrear, a Software Engineer with over 5 years of experience in full-stack development and workflow automation. I specialize in building intelligent automations using n8n, helping teams streamline operations and boost productivity. I’m also an expert in developing custom n8n nodes, with published work on npm - including the @vlm-run/n8n-nodes-vlmrun package. Linkedin - https://www.linkedin.com/in/shahrear-amin/ Email - shahrearbinamin33@gmail.com
このワークフローを共有