Loan Underwriting Analysis
Dies ist ein Document Extraction, AI Summarization-Bereich Automatisierungsworkflow mit 17 Nodes. Hauptsächlich werden Code, MistralAi, ManualTrigger, SplitInBatches, Agent und andere Nodes verwendet. Automatisierung der Dokumentenanalyse für Kreditentscheidungen mit Mistral OCR und GPT
- •OpenAI API Key
Verwendete Nodes (17)
{
"id": "rVKBWXqaa79EfTVA",
"meta": {
"instanceId": "db1715da5f21adba44ce4ea3b08abb06cd1771e876f5ad2751fcafd78c5eb9dc",
"templateCredsSetupCompleted": true
},
"name": "UnderwritingLoanAnalysis",
"tags": [],
"nodes": [
{
"id": "0d40759f-812a-4972-ba74-e42c8d5aa258",
"name": "Ordner durchsuchen",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
624,
0
],
"parameters": {
"query": "<Your Folder Name>",
"resource": "folder",
"operation": "search"
},
"credentials": {
"microsoftOneDriveOAuth2Api": {
"id": "<Your One Drive API Key>",
"name": "Microsoft Drive account"
}
},
"typeVersion": 1
},
{
"id": "65de0a29-5e09-41ae-b14c-e83a10eb1be5",
"name": "Elemente in einem Ordner abrufen",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
832,
0
],
"parameters": {
"folderId": "={{ $json.id }}",
"resource": "folder"
},
"credentials": {
"microsoftOneDriveOAuth2Api": {
"id": "<Your One Drive API Key>",
"name": "Microsoft Drive account"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "bdfdb814-df76-42ff-8b07-926c7e7d48c2",
"name": "Datei herunterladen",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
1216,
80
],
"parameters": {
"fileId": "={{ $('Get items in a folder').item.json.id }}",
"operation": "download"
},
"credentials": {
"microsoftOneDriveOAuth2Api": {
"id": "<Your One Drive API Key>",
"name": "Microsoft Drive account"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "bcd0718c-df22-41e1-9754-a2298877ae43",
"name": "Text extrahieren",
"type": "n8n-nodes-base.mistralAi",
"position": [
1376,
80
],
"parameters": {
"options": {}
},
"credentials": {
"mistralCloudApi": {
"id": "<Your OCR API Key>",
"name": "Mistral Cloud account"
}
},
"typeVersion": 1
},
{
"id": "6eaee806-a5e6-4c5d-b89a-500bd70cc03d",
"name": "Datei klassifizieren",
"type": "n8n-nodes-base.code",
"position": [
1584,
80
],
"parameters": {
"jsCode": "// get filename from Download node\nconst fileName = ($('Download a file').first().json.name || '').toLowerCase();\n\n// get extracted text from OCR node\nconst text = ($input.first().json.extractedText || '').toLowerCase();\n\nlet type = \"Unknown\";\n\n// --- Rule-based classification ---\n\n// Priority 1: File name clues\nif (fileName.includes(\"passport\")) type = \"Passport\";\nelse if (fileName.includes(\"license\") || fileName.includes(\"dl\")) type = \"Driving License\";\nelse if (fileName.includes(\"mortgage\")) type = \"Mortgage Application\";\nelse if (fileName.includes(\"proof\") && fileName.includes(\"fund\")) type = \"Proof of Funds Letter\";\nelse if (fileName.includes(\"pay\") || fileName.includes(\"paystub\")) type = \"Employee Pay Statement\";\nelse if (fileName.includes(\"t4\")) type = \"T4 Statement\";\nelse if (fileName.includes(\"electric\") || fileName.includes(\"hydro\")) type = \"Electricity Bill\";\nelse if (fileName.includes(\"internet\") || fileName.includes(\"shaw\")) type = \"Internet Bill\";\nelse if (fileName.includes(\"statement\") && fileName.includes(\"account\")) type = \"Account Statement\";\nelse if (fileName.includes(\"bank\")) type = \"Bank Statement\";\n\n// Priority 2: Text-based fallback\nelse if (text.includes(\"gross pay\") || text.includes(\"net pay\")) type = \"Employee Pay Statement\";\nelse if (text.includes(\"bank of montreal\") || text.includes(\"scotiabank\") || text.includes(\"royal bank\")) type = \"Bank Statement\";\nelse if (text.includes(\"proof of funds\")) type = \"Proof of Funds Letter\";\nelse if (text.includes(\"mortgage application\")) type = \"Mortgage Application\";\nelse if (text.includes(\"driver\") && text.includes(\"licence\")) type = \"Driving License\";\nelse if (text.includes(\"internet\") && text.includes(\"usage\")) type = \"Internet Bill\";\nelse if (text.includes(\"hydro\") || text.includes(\"electricity\")) type = \"Electricity Bill\";\nelse if (text.includes(\"t4\") && text.includes(\"income\")) type = \"T4 Statement\";\n\nreturn [{\n json: {\n FileName: $('Download a file').first().json.name,\n DocumentType: type,\n ExtractedText: $input.first().json.extractedText\n }\n}];\n"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "15d653cd-af01-43a1-ac1d-1497774745dd",
"name": "Daten zusammenführen",
"type": "n8n-nodes-base.code",
"position": [
1248,
-256
],
"parameters": {
"jsCode": "// Gather all items coming from the \"Done\" output of the Loop Over Items node\nconst docs = $input.all().map(item => ({\n FileName: item.json.FileName || null,\n DocumentType: item.json.DocumentType || \"Unknown\",\n ExtractedText: item.json.ExtractedText || \"\"\n}));\n\nreturn [{\n json: {\n BorrowerName: \"Kenneth Smith\", // replace with dynamic value if available\n Documents: docs\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "fa0b2bc5-2038-4b94-8650-5908298c64dc",
"name": "KI-Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1392,
-256
],
"parameters": {
"text": "=You will receive an array of documents belonging to a single mortgage applicant.\n\nEach document object includes:\n- FileName \n- DocumentType \n- ExtractedText (the OCR text from the original file)\n\nAnalyze the full dataset, identify document types, extract key financial information, and produce an underwriting summary and decision as described in the system prompt.\n\nBorrower Documents:\n{{ JSON.stringify($json.Documents, null, 2) }}\n",
"options": {
"systemMessage": "=You are a senior mortgage underwriter at a Canadian financial institution.\n\nYou will analyze a borrower’s full document set to determine mortgage eligibility, loan feasibility, and documentation completeness.\n\nYour analysis must include:\n\n### 1. Identity Verification\nConfirm borrower identity, address, and citizenship using ID documents (Passport, Driver’s License, Utility Bills).\n\n### 2. Employment & Income Verification\nValidate employment details, employer name, job title, tenure, and consistency of pay across pay statements, T4s, and tax filings.\n\n### 3. Asset & Liability Review\nSummarize checking, savings, and investment balances. \nIdentify recurring debts or monthly obligations (utilities, rent, phone, insurance, etc.). \nCalculate Debt-to-Income (DTI) ratio.\n\n### 4. Property & Loan Analysis\nIf a mortgage application or loan-related document is present, extract:\n- Lender name and officer\n- Loan amount and term\n- Interest rate type (fixed / variable)\n- Loan purpose (purchase / refinance)\n- Down payment and percentage\n- Property value and address\n- Property type and use (primary, investment, secondary)\n- Amortization structure\n- Derived Loan-to-Value (LTV = loan amount ÷ property value)\nThen evaluate:\n- Whether the borrower’s verified assets can support the required down payment.\n- Whether DTI and LTV fall within standard underwriting thresholds.\n- Any property or loan risks (e.g., old property, low down payment, non-owner-occupied use).\n\n### 5. Document Consistency\nIdentify missing, inconsistent, or outdated documents (expired IDs, missing pay stubs, missing credit report).\n\n### 6. Decision\nProvide a professional underwriter-style decision with justification:\n- **Decision:** Approve / Approve with conditions / Decline / Escalate\n- **Rationale:** Clear bullet points explaining the reasoning.\n- **Next Steps:** Requested documents or verifications before final approval.\n\n### Output Format\nReturn your analysis as Markdown:\n\n#### Step 1: Identity Verification\n#### Step 2: Employment & Income\n#### Step 3: Assets & Liabilities\n#### Step 4: Property & Loan Analysis\n#### Step 5: Document Consistency\n#### Step 6: Final Decision\n#### Decision Summary (bullet points)\n"
},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "1be14652-9fa5-473b-afc8-901a0ec4ed07",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1392,
-112
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "<Your LLM Model Name>"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "<Your LLM Model API Key>",
"name": "OpenAi account 2"
}
},
"typeVersion": 1.2
},
{
"id": "e5fe5cff-e538-4032-8df5-1246099618d1",
"name": "Bei Klick auf 'Workflow ausführen'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
432,
0
],
"parameters": {},
"typeVersion": 1
},
{
"id": "30b481ed-670c-4303-a0da-7362e94fa2d4",
"name": "Notizzettel",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
176
],
"parameters": {
"color": 4,
"width": 816,
"content": "**Solution: \n\ntrigger the run, grab files from a known OneDrive folder, loop in batches, OCR each file, classify it with simple filename+text rules, aggregate into a borrower payload, then have the LLM return JSON first and a brief Markdown decision. Add filters/retries, bucket unknown/unreadable docs, log counts/costs, and keep PII out of logs.**"
},
"typeVersion": 1
},
{
"id": "9ea5459a-21f6-4e75-830b-b4b38400f089",
"name": "Notizzettel1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-224
],
"parameters": {
"color": 4,
"width": 816,
"content": "**Problem Statement**\n\nUnderwriters receive borrower documents in mixed formats and naming conventions (IDs, paystubs, bank statements, utility bills, tax forms). Manually opening, reading, and sorting these files is slow and error-prone. Two big pain points: 1) reliably extracting text from scans, and 2) consistently identifying document types to assemble a complete borrower picture. This leads to missed docs, inconsistent decisions, weak audit trails, and high turnaround time—especially when multiple borrowers are involved."
},
"typeVersion": 1
},
{
"id": "4d426895-0b7f-4ea1-a38f-5188801f586a",
"name": "Notizzettel2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-32
],
"parameters": {
"color": 4,
"width": 816,
"height": 176,
"content": "***Constraints***\n\nFiles live in OneDrive folders with variable naming.\nQuality of scans varies; OCR can fail or return partial text.\nDocument classification needs to be understandable and easily adjustable.\nPII must not leak through logs or exports.\nCosts (OCR + LLM tokens) rise with folder size and page counts.\nYou need a deterministic path when AI isn’t confident (fallbacks, flags)."
},
"typeVersion": 1
},
{
"id": "844083c1-ce99-4ab3-98b7-7a6523d88109",
"name": "Über Elemente iterieren",
"type": "n8n-nodes-base.splitInBatches",
"disabled": true,
"position": [
1040,
0
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "40f0d23a-aae0-4450-959e-3b98032659c2",
"name": "Notizzettel3",
"type": "n8n-nodes-base.stickyNote",
"position": [
368,
-144
],
"parameters": {
"width": 208,
"height": 112,
"content": "Entry trigger used for local testing and manual runs; it simply starts the pipeline and hands off to the OneDrive folder search."
},
"typeVersion": 1
},
{
"id": "781728d1-9f06-4e95-adfc-ae2095771027",
"name": "Notizzettel4",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
-144
],
"parameters": {
"width": 320,
"height": 112,
"content": "Finds the target borrower documents container in OneDrive and outputs the folder id that downstream nodes use, Takes the found folder id and lists the files inside so the loop can process each item"
},
"typeVersion": 1
},
{
"id": "8425b303-96cc-4ff9-ba20-a386a300519d",
"name": "Notizzettel5",
"type": "n8n-nodes-base.stickyNote",
"position": [
992,
288
],
"parameters": {
"width": 768,
"height": 256,
"content": "**Loop Over** : Drives per-file processing: for each listed file it routes to download/OCR/classify, and when the last item is done it forwards the collected results to the combiner. \n\n**Download a file (OneDrive)**: Fetches the actual file binary (plus metadata) for the current item so OCR can read its contents.\n\n**Extract text (Mistral AI)**: Runs OCR on the downloaded file and emits the extracted text that classification and later analysis depend on.\n\n**Classify the File (Code)**: Uses filename clues and OCR text to assign a document type (e.g., Passport, Paystub, Bank Statement, Utility Bill, T4, Proof of Funds, Mortgage Application, or Unknown) and forwards a compact record per file."
},
"typeVersion": 1
},
{
"id": "f55f83eb-f7b7-4982-99c1-ec21f573793c",
"name": "Notizzettel6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1200,
-432
],
"parameters": {
"width": 560,
"content": "**Combine the Data (Code)**: Aggregates all per-file records into a single borrower payload with BorrowerName and a Documents[] array ready for underwriting analysis. \n**AI Agent (@n8n/n8n-nodes-langchain.agent)**: Consumes the consolidated Documents[], applies an underwriting-oriented system prompt, and produces the decision-focused analysis for the borrower. Provides the language model (gpt-4.1-mini) that the AI Agent uses to generate the underwriting summary and decision.\n"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "b3d81169-9b6f-4530-b765-1ab386b90e4a",
"connections": {
"bcd0718c-df22-41e1-9754-a2298877ae43": {
"main": [
[
{
"node": "6eaee806-a5e6-4c5d-b89a-500bd70cc03d",
"type": "main",
"index": 0
}
]
]
},
"bdfdb814-df76-42ff-8b07-926c7e7d48c2": {
"main": [
[
{
"node": "bcd0718c-df22-41e1-9754-a2298877ae43",
"type": "main",
"index": 0
}
]
]
},
"844083c1-ce99-4ab3-98b7-7a6523d88109": {
"main": [
[
{
"node": "15d653cd-af01-43a1-ac1d-1497774745dd",
"type": "main",
"index": 0
}
],
[
{
"node": "bdfdb814-df76-42ff-8b07-926c7e7d48c2",
"type": "main",
"index": 0
}
]
]
},
"0d40759f-812a-4972-ba74-e42c8d5aa258": {
"main": [
[
{
"node": "65de0a29-5e09-41ae-b14c-e83a10eb1be5",
"type": "main",
"index": 0
}
]
]
},
"15d653cd-af01-43a1-ac1d-1497774745dd": {
"main": [
[
{
"node": "fa0b2bc5-2038-4b94-8650-5908298c64dc",
"type": "main",
"index": 0
}
]
]
},
"6eaee806-a5e6-4c5d-b89a-500bd70cc03d": {
"main": [
[
{
"node": "844083c1-ce99-4ab3-98b7-7a6523d88109",
"type": "main",
"index": 0
}
]
]
},
"1be14652-9fa5-473b-afc8-901a0ec4ed07": {
"ai_languageModel": [
[
{
"node": "fa0b2bc5-2038-4b94-8650-5908298c64dc",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"65de0a29-5e09-41ae-b14c-e83a10eb1be5": {
"main": [
[
{
"node": "844083c1-ce99-4ab3-98b7-7a6523d88109",
"type": "main",
"index": 0
}
]
]
},
"e5fe5cff-e538-4032-8df5-1246099618d1": {
"main": [
[
{
"node": "0d40759f-812a-4972-ba74-e42c8d5aa258",
"type": "main",
"index": 0
}
]
]
}
}
}Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Experte - Dokumentenextraktion, KI-Zusammenfassung
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Vinay Gangidi
@vgangidiDiesen Workflow teilen