This workflow corresponds to n8n.io template #15852 — we link there as the canonical source.
This workflow follows the Form Trigger → Google Sheets 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": "Vc7e9iEDsCjoXsdM",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "KYC-RISK-FORM",
"tags": [],
"nodes": [
{
"id": "5406944c-aa51-4edf-8345-c34de0359e00",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-176,
-336
],
"parameters": {
"width": 688,
"height": 608,
"content": "## KYC Risk Profiling Workflow\n\nCaptures KYC form data, validates required fields, sends it to AI for risk analysis, formats the response and routes records based on risk level.\n\n## Flow:\n\nKYC Form Submission \u2192 Validate KYC Input \u2192 AI Risk Analysis \u2192 Process AI Response \u2192 Format Final Data \u2192 IF Risk Check\n\n\n## Setup Steps\n\nCreate a KYC form with exact field names for all required inputs. Configure the validation node to reject missing or invalid data. Ensure the AI node returns structured JSON. Map final fields correctly in Google Sheets and connect Slack so alerts trigger only when the processed riskCategory is High Risk.\n\n\n## How It Works\n\nWhen a user submits the KYC form, the workflow validates the input and sends clean data to AI for risk scoring and profiling. The AI response is parsed, formatted and checked for risk level. High-risk cases are logged and alerted in Slack, while low and medium-risk cases are only saved."
},
"typeVersion": 1
},
{
"id": "af556160-67c5-409f-a81b-68c51e0c923d",
"name": "KYC Form Submission",
"type": "n8n-nodes-base.formTrigger",
"position": [
576,
768
],
"parameters": {
"options": {},
"formTitle": "KYC_FORM",
"formFields": {
"values": [
{
"fieldName": "Income",
"fieldType": "number",
"fieldLabel": "e.g.5000",
"requiredField": true
},
{
"fieldName": "Geography",
"fieldLabel": "e.g.india,usa",
"requiredField": true
},
{
"fieldName": "Occupation",
"fieldLabel": "e.eg.software engineer",
"requiredField": true
}
]
}
},
"typeVersion": 2.4
},
{
"id": "32b37622-fd04-49f3-aecc-4441bc120ce1",
"name": "Process AI Response",
"type": "n8n-nodes-base.code",
"position": [
1376,
768
],
"parameters": {
"jsCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n try {\n // Correct path for your AI response\n let rawText = item.json.output?.[0]?.content?.[0]?.text || '{}';\n\n // Remove markdown fences if present\n rawText = rawText\n .replace(/```json/g, '')\n .replace(/```/g, '')\n .trim();\n\n const parsed = JSON.parse(rawText);\n\n results.push({\n json: {\n riskCategory: parsed.riskCategory || 'Unknown',\n redFlags: parsed.redFlags || [],\n redFlagText: (parsed.redFlags && parsed.redFlags.length > 0)\n ? parsed.redFlags.join(', ')\n : 'None',\n income: parsed.income || '',\n geography: parsed.geography || '',\n occupation: parsed.occupation || ''\n }\n });\n\n } catch (error) {\n results.push({\n json: {\n riskCategory: 'Unknown',\n redFlags: [],\n redFlagText: 'None',\n income: '',\n geography: '',\n occupation: '',\n error: error.message\n }\n });\n }\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "e591b2ac-d634-42b4-9ac9-b738ec0ba1f0",
"name": "Format Final Data",
"type": "n8n-nodes-base.set",
"position": [
1600,
768
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c10e471b-3900-49da-a84a-ba498d1e6249",
"name": "riskCategory",
"type": "string",
"value": "={{ $json.riskCategory }}"
},
{
"id": "0fa31d67-d34a-4cb7-b467-376d4f2ba100",
"name": "redFlags",
"type": "string",
"value": "={{ $json.redFlags }}"
},
{
"id": "c0f4121f-3c2e-44c6-adbc-be6063178ce8",
"name": "income",
"type": "string",
"value": "={{ $json.income }}"
},
{
"id": "b516a79a-474c-4870-acad-3de36a937ff4",
"name": "geography",
"type": "string",
"value": "={{ $json.geography }}"
},
{
"id": "4fb86d75-e107-4db9-b486-675e710823b7",
"name": "occupation",
"type": "string",
"value": "={{ $json.occupation }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "f95c9c9f-8a6a-403e-9c44-80cf8f140880",
"name": "Check High Risk",
"type": "n8n-nodes-base.if",
"position": [
1824,
768
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f3403896-dee4-4855-8b75-43ef4deb4233",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.riskCategory }}",
"rightValue": "High"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "11bb277c-141f-4885-846a-03d68cf4af36",
"name": "Save High Risk Record",
"type": "n8n-nodes-base.googleSheets",
"position": [
2272,
672
],
"parameters": {
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.7
},
{
"id": "8867854e-40fa-4224-b42d-7d851013ce25",
"name": "Send High Risk Alert",
"type": "n8n-nodes-base.slack",
"position": [
2496,
672
],
"parameters": {
"text": "= *HIGH RISK KYC Alert!* \n*Income:* {{ $json.income }} \n*Geography:* {{ $json.geography }} \n*Occupation:* {{ $json.occupation }} \n*Risk Category:* {{ $json.riskCategory }} \n*Red Flags:* - {{ $json.redFlagText }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": ""
},
"otherOptions": {}
},
"typeVersion": 2.4
},
{
"id": "d17c8d0d-11e5-4d25-9e39-a1d5eef7f1f1",
"name": "Save Normal Risk Record",
"type": "n8n-nodes-base.googleSheets",
"position": [
2080,
864
],
"parameters": {
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.7
},
{
"id": "9ae34016-ba2e-41af-942f-3787befeecf9",
"name": "Validate KYC Input",
"type": "n8n-nodes-base.code",
"position": [
800,
768
],
"parameters": {
"jsCode": "const income = Number($json.Income || 0);\nconst geography = String($json.Geography || '').trim();\nconst occupation = String($json.Occupation || '').trim();\n\nconst errors = [];\n\nif (!income || income <= 0) {\n errors.push('Income must be greater than 0');\n}\n\nif (!geography) {\n errors.push('Geography is required');\n}\n\nif (!occupation) {\n errors.push('Occupation is required');\n}\n\nreturn [\n {\n json: {\n Income: income,\n Geography: geography.toUpperCase(),\n Occupation: occupation,\n isValid: errors.length === 0,\n validationErrors: errors.length ? errors.join(', ') : '',\n createdAt: new Date().toISOString()\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "fca703bd-9b1f-4558-82d5-fe6aeae3ba3c",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
448
],
"parameters": {
"color": 7,
"width": 720,
"height": 576,
"content": "## KYC Form Submission\n\nTriggers the workflow when a customer submits KYC details and passes the entered information into the risk profiling process."
},
"typeVersion": 1
},
{
"id": "8f26c1c0-ef85-4435-8b42-ec6997cca255",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1344,
448
],
"parameters": {
"color": 7,
"width": 608,
"height": 576,
"content": "## AI Response Formatting\n\nProcesses the AI-generated risk analysis, extracts the important customer risk fields, formats the output into a clean structure and prepares the data for the final decision step where the workflow checks whether the customer should be treated as high risk."
},
"typeVersion": 1
},
{
"id": "c24f8b7d-2722-4736-b20e-c38fb033e0ea",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2032,
448
],
"parameters": {
"color": 7,
"width": 640,
"height": 576,
"content": "## AI Response Formatting\n\nProcesses the AI risk assessment, extracts key risk fields, formats the customer data into a clean final structure and prepares the record for the decision step that determines whether the customer should be routed through the high-risk review path."
},
"typeVersion": 1
},
{
"id": "5f6aee12-41c1-4d8f-9c6a-b14108723f1a",
"name": "Format the Data For Sheet",
"type": "n8n-nodes-base.set",
"position": [
2080,
672
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c686274f-926b-4abe-9289-827f2e55f86f",
"name": "riskCategory",
"type": "string",
"value": "={{ $json.riskCategory }}"
},
{
"id": "78e829d0-a59e-4ae6-9f35-ed26139501e2",
"name": "income",
"type": "string",
"value": "={{ $json.income }}"
},
{
"id": "7d55e5b9-0b22-4ea0-b6bb-dc694dcc9681",
"name": "geography",
"type": "string",
"value": "={{ $json.geography }}"
},
{
"id": "8052eefb-9fb4-4251-92d9-bd0148e4a303",
"name": "redFlags",
"type": "string",
"value": "={{ $json.redFlags }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "bf2f25cd-52ad-4f70-be1d-c4d92d36b218",
"name": "Ai Assign The Risk Category",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1008,
768
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {},
"responses": {
"values": [
{
"content": "=You are a KYC Risk Analyst.\n\nAnalyze the applicant details below and do ALL of the following:\n1. Assign a risk category: Low / Medium / High\n2. List any red flags found\n3. Return the original applicant details exactly as received\n\nApplicant Details:\nIncome: {{ $json.Income }}\nGeography: {{ $json.Geography }}\nOccupation: {{ $json.Occupation }}\n\nRisk Rules:\n- High risk if the geography is a sanctioned country, FATF blacklisted country or high-risk jurisdiction\n- High risk if the occupation is in a high-risk sector such as cryptocurrency, gambling, arms trade, shell companies or politically exposed roles\n- Medium risk if one moderate concern exists\n- Low risk if no major red flags exist\n\nReturn ONLY valid JSON in this exact format:\n{\n \"riskCategory\": \"High\",\n \"redFlags\": [\"flag1\", \"flag2\"],\n \"income\": \"{{ $json.Income }}\",\n \"geography\": \"{{ $json.Geography }}\",\n \"occupation\": \"{{ $json.Occupation }}\"\n}"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "c8041ceb-3ab5-48e6-8344-ddea3edb7b87",
"connections": {
"Check High Risk": {
"main": [
[
{
"node": "Format the Data For Sheet",
"type": "main",
"index": 0
}
],
[
{
"node": "Save Normal Risk Record",
"type": "main",
"index": 0
}
]
]
},
"Format Final Data": {
"main": [
[
{
"node": "Check High Risk",
"type": "main",
"index": 0
}
]
]
},
"Validate KYC Input": {
"main": [
[
{
"node": "Ai Assign The Risk Category",
"type": "main",
"index": 0
}
]
]
},
"KYC Form Submission": {
"main": [
[
{
"node": "Validate KYC Input",
"type": "main",
"index": 0
}
]
]
},
"Process AI Response": {
"main": [
[
{
"node": "Format Final Data",
"type": "main",
"index": 0
}
]
]
},
"Save High Risk Record": {
"main": [
[
{
"node": "Send High Risk Alert",
"type": "main",
"index": 0
}
]
]
},
"Format the Data For Sheet": {
"main": [
[
{
"node": "Save High Risk Record",
"type": "main",
"index": 0
}
]
]
},
"Ai Assign The Risk Category": {
"main": [
[
{
"node": "Process AI Response",
"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.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow captures customer KYC details through an n8n Form, validates the submitted input, sends the cleaned data to OpenAI for automated risk profiling, formats the AI response and routes the result based on whether the applicant is classified as High Risk or not.…
Source: https://n8n.io/workflows/15852/ — 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.
Customer Feedback Loop Analyzer. Uses formTrigger, lmChatGoogleGemini, gmail, slack. Event-driven trigger; 11 nodes.
This workflow is for eCommerce researchers, affiliate marketers, and anyone who needs to compare product listings across sites like Amazon. It’s perfect for quickly identifying top product picks based
YouTube Strategist. Uses formTrigger, splitOut, splitInBatches, agent. Event-driven trigger; 50 nodes.
This advanced multi-phase n8n workflow automates the complete research, analysis, and ideation pipeline for a YouTube strategist. It scrapes competitor channels, analyzes top-performing titles and thu
This workflow delivers a complete, enterprise-grade Gmail automation system designed for high-volume teams. It classifies incoming emails, applies labels, generates AI-powered responses, and routes me