WhatsApp Automated HR Service System: GPT Classification + Google Workspace
Employee sends WhatsApp message → LLM classifies intent → routes to 5 specialized AI agents → auto-processes leave, attendance, FAQ, complaints, candidate shortlisting → replies via WhatsApp
- Who
- HR teams, startups, and enterprises needing automated employee request handling
- You get
- Automatically process leave approvals, attendance check-ins, HR policy Q&A, complaint escalation emails, and candidate screening with interview scheduling via WhatsApp
- You need
- n8n · whatsapp · google-sheets · google-calendar · supabase
Constraints
Prerequisites: n8n instance; WhatsApp Business API credentials (Twilio or Meta); OpenAI API key; Google Sheets/Calendar/Gmail OAuth2; Supabase vector store. Costs: OpenAI per-token; WhatsApp Business API per-message; Google Workspace per subscription. Note: Google Sheets document IDs, Supabase table names, office geo-fence coordinates, and WhatsApp phone numbers in workflow.json are placeholders and must be replaced.
What they did
Author tnayagarwal published a 65-node n8n template that uses WhatsApp as the employee entry point to an HR system. Employees send text, location, audio, or image messages; the workflow classifies intent with GPT-4o, routes to 5 specialized AI agents for leave, attendance, FAQ, complaints, and candidate shortlisting, and replies with results via WhatsApp.
How it went
The template has 22,613 views on n8n.io (author_report). Full node connections and runnable prompt configurations are shown, but this site has not imported or run the workflow.
Worth knowing
1. Office geo-fence coordinates in Code1 node are an empty array and must be filled with actual lat/lon. 2. Google Sheets document IDs are the author's private spreadsheets and must be replaced. 3. WhatsApp phoneNumberId and recipientPhoneNumber are hardcoded and must be updated. 4. The CV download sub-workflow contains a specific Google Drive file ID to replace. 5. 'ICICI' appears throughout as an example company name and should be replaced. 6. Supabase vector store table name defaults to 'data' and must match your actual policy documents table. 7. The author uses a mix of gpt-4.1-nano, gpt-4o-mini, and gpt-4o models, not a single model.
n8n workflow template
Structure checked · Not run-testedUse “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.
Setup and test checklist
Credentials to connect
- WhatsApp Trigger node: connect whatsAppTriggerApi credentials.
- OpenAI node: connect OpenAI API credentials.
- OpenAI Chat Model node: connect OpenAI API credentials.
- HTTP Request node: connect HTTP Header Auth credentials.
- HTTP Request1 node: connect HTTP Header Auth credentials.
- OpenAI1 node: connect OpenAI API credentials.
- OpenAI Chat Model3 node: connect OpenAI API credentials.
- OpenAI Chat Model1 node: connect OpenAI API credentials.
- Supabase Vector Store node: connect supabaseApi credentials.
- Embeddings OpenAI node: connect OpenAI API credentials.
- OpenAI Chat Model2 node: connect OpenAI API credentials.
- Gmail node: connect Gmail OAuth2 credentials.
- Personalize email node: connect OpenAI API credentials.
- Google Calendar node: connect Google Calendar OAuth2 credentials.
- Google Sheets2 node: connect Google Sheets OAuth2 credentials.
- OpenAI Chat Model4 node: connect OpenAI API credentials.
- Gmail1 node: connect Gmail OAuth2 credentials.
- JD tool node: connect Google Sheets OAuth2 credentials.
- applicants node: connect Google Sheets OAuth2 credentials.
- OpenAI Chat Model5 node: connect OpenAI API credentials.
- OpenAI Chat Model6 node: connect OpenAI API credentials.
- Gmail2 node: connect Gmail OAuth2 credentials.
- dept head email node: connect Google Sheets OAuth2 credentials.
- OpenAI Chat Model7 node: connect OpenAI API credentials.
- getrows node: connect Google Sheets OAuth2 credentials.
- putrows node: connect Google Sheets OAuth2 credentials.
- update leaves node: connect Google Sheets OAuth2 credentials.
- get leaves node: connect Google Sheets OAuth2 credentials.
- download media node: connect whatsAppApi credentials.
- download media1 node: connect whatsAppApi credentials.
- read sheets node: connect Google Sheets OAuth2 credentials.
- WhatsApp Responder node: connect whatsAppApi credentials.
- get mail node: connect Google Sheets OAuth2 credentials.
- WhatsApp Approval node: connect whatsAppApi credentials.
Configuration to replace
- Source template is n8n public workflow #4975 (~65 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
- Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.
Test input and expected output
- Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
- Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.
Template changes
- Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
- No business-logic edits; verify keys, quotas and privacy compliance before use.
Template retrieved: 2026-10-24
Steps
Configure trigger and LLM message classifier
Import the template into n8n. Configure the WhatsApp Trigger node to receive messages updates. Connect the Delegatory LLM node (Basic LLM Chain) using gpt-4o. This node analyzes the incoming message type and text.body, outputting a single digit 1-5: 1=leave, 2=HR Q&A, 3=attendance (location type), 4=complaint/request, 5=candidate shortlisting. Audio or image messages are also classified as 2.
Execution prompt · Source text。Delegatory LLM node (Basic LLM Chain) text parameter; promptType=define
=You are given a message object with the structure: type: {{ $json.messages[0].type }} text body (if applicable): {{ $json.messages[0].text.body }} Your task is to analyze the message and classify it into exactly one category, returning only the corresponding number, based on the detailed rules below. 📩 If the type is "text": Analyze the content in {{ $json.messages[0].text.body }} and classify based on the user's intent: ✅ Output 1 → Leave Request Use this only if the message is about applying for leave, informing absence, or time off. Examples: “I need leave for tomorrow.” “I won’t be coming in today.” “Apply leave from 12th to 14th.” ✅ Output 2 → HR Chatbot (FAQ or Policy Queries) Use this for any general queries about HR policies, benefits, leave balances, holidays, or onboarding. Examples: “How many leaves do I have left?” “What is the dress code policy?” “Where can I get my salary slip?” ✅ Output 5 → Shortlisting Request Use this if the user is instructing to filter, rank, or shortlist candidates for a particular job or JD. Examples: “Shortlist candidates for backend role.” “Filter CVs for the UI designer position.” ✅ Output 4 → Request or Complaint for Department Head Use this if the user is requesting to send an email to or escalate an issue to a department head or authority. Examples: “Raise a complaint to admin.” “Send a mail to IT about my laptop.” “Escalate this matter to HR.” 📍 If the type is "location": This indicates attendance marking via GPS. ✅ Output 3 🎙️ If the type is "audio" or "image": Assume this is a general HR query via media. For example, a voice message asking for policy info or a photo of a document. ✅ Output 2 🔴 Final & Strict Instruction: You must return only one of the following numbers: 1, 2, 3, 4, or 5 No text. No description. No formatting. Only the number.Switch routing to corresponding agent
Add a Switch node that routes based on the LLM output digit to 5 branches: 1→Leave Agent, 2→HR FAQ Agent, 3→Attendance Marking, 4→Escalation Agent, 5→Shortlisting Agent. Use Merge nodes after each branch to bring original WhatsApp data back for downstream agent processing.
Leave Agent: leave approval and escalation
The Leave Agent (AI Agent node, gpt-4.1-nano) receives leave requests. It queries employee available leaves via Google Sheets tools; if duration<2 days and sick leave, auto-approves and sends Gmail (CC dept head); if ≥2 days or non-sick, forwards to dept head for approval. Replies via WhatsApp when no leaves remain. Uses update leaves / get leaves tools to read/write Google Sheets.
Execution prompt · Source text。Leave Agent node (AI Agent) text parameter; promptType=define
=You are an autonomous leave request assistant for ICICI's internal HR system. You receive leave requests from employees through WhatsApp in plain text {{ $json.messages[0].text.body }}- this is the leave request text and details use the above - “I need a sick leave on 11th June” - “I'm applying for medical leave from 11th to 14th June” - “Can I take a personal leave tomorrow?” Your goal is to process each leave request correctly based on live employee data and respond with the appropriate action. Tools You Can Use: 1. **Google Sheets – Get Rows Tool** - Use this to retrieve employee records - Sheet contains the following columns: - `name`, `email`, `department head email`, `available leaves`, `last leave`, `attendance`, `department` 2. **Google Sheets – Append or Update Rows Tool** - Use this to log any leave taken or updates if needed 3. **Gmail Tool** - Use this to send emails (e.g. approvals, forwarding to department heads) Input Format: - Each leave request comes from WhatsApp and contains: - **Text** of the request (e.g. “I need a sick leave on 11th June”) - **Name** of the requester, from WhatsApp contact: `{{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }}` Your Step-by-Step Logic: 1. **Extract the following from the message:*{{ $json.messages[0].text.body }}* - Dates requested (single or range) 2. **Match the WhatsApp user’s name** {{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }}with the **name** column in the Google Sheet using the `Get Rows` tool. 3. **Check the employee’s available leaves.** - If available leaves ≥ 1: - ✅ **Sick leave for 1 day**: - Compose an approval email to the employee’s email - CC the department head - Email body should include the leave date and confirmation - Use Gmail Tool to send - Send WhatsApp message: > “Your sick leave has been approved. Please check your email.” - ✅ **Multi-day or non-sick leave**: - Compose a **leave request email to the department head** - Include reason, dates, and requester’s name - CC the employee - Send WhatsApp message: > “Your leave request has been forwarded to your department head for approval.” - ❌ If no available leaves: - Do not send email - Send WhatsApp message: > “You currently have no available leaves. Please contact HR if you believe this is an error.” - Hallucinate any leave status - Invent dates or assume approval - Reply with personal opinionsAttendance Agent: GPS attendance check-in
The Code node (Code1) uses the Haversine formula to calculate distance between employee GPS location and office polygon vertices, determining isInsideOffice. The Attendance Agent (AI Agent, gpt-4o) then: if not in office, asks to resend location; if in office, queries Google Sheets (getrows/putrows), writes Entry Time if no record, updates Exit Time if record exists without exit, or notifies if already complete. Supports overtime calculation.
Execution prompt · Source text。Code1 node (Code) jsCode parameter; officePolygon coordinates must be filled
// Earth radius in meters const R = 6371000; // Convert degrees to radians const toRad = deg => deg * Math.PI / 180; // Extract coordinates from the input JSON safely const inputJson = $input.first().json; let lat, lon; if (inputJson.messages && Array.isArray(inputJson.messages) && inputJson.messages[0] && inputJson.messages[0].location) { lat = inputJson.messages[0].location.latitude; lon = inputJson.messages[0].location.longitude; } else { // Handle missing data as needed; here, we return an error object return [{ json: { error: "Missing location data in input" } }]; } // Office polygon vertices [longitude, latitude] const officePolygon = [ ]; // Set distance threshold (increase for more leeway) const distanceThreshold = 2500; let isNearby = false; // Haversine distance function function haversine(lat1, lon1, lat2, lon2) { const dLat = toRad(lat2 - lat1); const dLon = toRad(lon2 - lon1); const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } // Check if user is within threshold distance of any polygon point for (const [polyLon, polyLat] of officePolygon) { const distance = haversine(lat, lon, polyLat, polyLon); if (distance <= distanceThreshold) { isNearby = true; break; } } // Output result with user's location and isInsideOffice flag return [{ json: { ...$input.first().json, latitude: lat, longitude: lon, isInsideOffice: isNearby } }];Execution prompt · Source text。Attendance Agent node (AI Agent) text parameter; promptType=define
=Follow the steps below precisely: Step 1: Location Check the value is true If false, output only this exact message: "not in office please resend loc when inside the building" If true, proceed to Step 2. Step 2: Extract User Info Extract the following: User Name → {{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }} Current DateTime → {{ $now }} Format it as: hh:mm, DD-MM-YYYY Step 3: Google Sheet Attendance Logic use the getrows tool and search for a row where: Name equals {{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }} Date equals today (based on formatted {{ $now }}) Then: Case A: No matching row found ➕ Create a new row with the following: using putrows tool Name: {{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }} Date: today Name : {{ $json.contacts[0].profile.name }} Entry Time: current time (hh:mm), Date ( eg: 11th june, 10am) Exit Time: (leave blank) Case B: Matching row exists & Exit Time is blank using getrows and putrows tool 🕓 Update the existing row’s Exit Time with current time. Case C: Matching row exists & Exit Time is already filled ✅ Do nothing or optionally return: using google sheet 5 tool "You have already logged both entry and exit for today." Output Format: Return a message like: "Entry time logged: 09:45, 11-06-2025" "Exit time updated: 18:10, 11-06-2025" Or, if already marked: "You have already logged both entry and exit for today." 🔁 Summary: Only proceed if user is inside the office using {{ $json.isInsideOffice }} Use Google Sheets to track attendance per name per day. Log times in hh:mm, DD-MM-YYYY format. Avoid duplicate exit entries.HR FAQ Chatbot Agent: policy Q&A and media handling
The Verify Message Type Switch node distinguishes text/audio/image. Audio/images are downloaded via WhatsApp → HTTP Request → transcribed/analyzed by OpenAI (gpt-4o-mini), then fed to HR Chatbot. The HR Chatbot (AI Agent, gpt-4.1-nano) uses a systemMessage defining its role: for policy questions, call policy_vector_store (Supabase vector store + OpenAI Embeddings) to retrieve company policies; for attendance questions, query Google Sheets; for general FAQ, answer directly.
Execution prompt · Source text。HR Chatbot node (AI Agent) options.systemMessage parameter
You are an autonomous HR assistant chatbot for ICICI employees. You support inputs from text, audio, and image transcription. You have access to a tool called `icici_policy_vector_store` that lets you retrieve official ICICI HR policies and documents. When answering **any HR policy-related question** (e.g., about leave, holidays, code of conduct, dress code, hybrid policy), always use this tool internally to retrieve information and guide your response. Do not mention that you are using the tool, vector search, or any database. Simply respond as if you already know the answer. If the tool does not return any documents, respond clearly: > “I couldn’t find an official document for this, but here’s what I can share based on general HR practices.” You also have access to a Google Sheet containing employee attendance. When a user asks about their attendance: - Count how many rows match their name - Each row is a day present - Count how many of those have Entry Time ≤ 09:15 and Exit Time > 17:15 for overtime Respond like: “You were present for 20 days this month, with 5 days of overtime.” If a user thanks you or ends the conversation, close politely. Keep all responses professional, friendly, helpful, and aligned with ICICI’s HR voice.
Request/Complaint Agent: generate and send email to department head
The Email Agent (AI Agent, gpt-4o-mini) generates a formal email based on the WhatsApp message content. It looks up the department head email via the dept head email tool from Google Sheets, then sends via Gmail tool (CCing the employee).
Execution prompt · Source text。Email Agent node (AI Agent) text parameter; promptType=define
=based on {{ $('WhatsApp Trigger').item.json.messages[0].text.body }} , you need to generate an email for the users dept head from the google sheets tool and generate a mail based on whats in the whatspp message body itll be to the dept head email from the sheet and cc the user email. match using {{ $('WhatsApp Trigger').item.json.contacts[0].profile.name }} and generate a proper mail and send it with the gmail toolShortlisting Agent: candidate screening and interview scheduling
The Shortlist Agent (AI Agent, gpt-4o-mini) extracts JD and candidate data per WhatsApp instruction, uses an n8n sub-workflow tool to download and parse CVs, scores candidates 1-10, and outputs structured results (name, email, score, shortlist, reason, missing skills) to Google Sheets. The Book Meeting Agent (gpt-4o-mini) uses Google Calendar tool to schedule 30-min interviews 2 days later between 11:00-12:00. The WhatsApp Approval node sends a confirmation message; upon user confirmation, the Personalize email node drafts a personalized email and sends it via Gmail.
Execution prompt · Source text。Shortlist Agent node (AI Agent) text parameter; promptType=define
={{ $json.messages[0].text.body }} is the user input. use the JD sheet tool to extract the respective JD for the given poistion in the user input. use the applicants sheets tool to extract applicant data , only name, email phone, you have a filter for returning only rows matching the required "applied for" role use n8n tool to get cv text and compare with jd and make reaons for required output parser content always return a new output with proper reasoning give a score 1-10 based on exp, relevance of projects and listed skillsExecution prompt · Source text。Book Meeting node (AI Agent) text parameter; promptType=define
=create a meeting for the user based on google calendar tool. meeting should be 2 days after {{ $today }} and between 11 and 12pm and 30 mins long. dont forget to output time and date in the message with human readable formattingExecution prompt · Source text。Personalize email node (OpenAI) messages[0].content parameter
=You are an HR assistant generating personalized recruitment emails based on candidate data for ICICI bank (mention in subject and content). Below is a candidate’s information: the input instructions are {{ $('WhatsApp Trigger').item.json.messages[0].text.body }}. extract number of candidates and poistion from this Name: {{ $('Google Sheets2').item.json.Name }} Email:{{ $('Shortlist Agent').item.json.output.email }} Shortlist Status: {{ $('Google Sheets2').item.json.Shortlist }} message {{ $('Book Meeting').item.json.output.message }} Write a professional email: - If the candidate is shortlisted (`Shortlist` is "yes"): - Congratulate the candidate on being shortlisted. - Mention the position and the interview timings. mention in normal date time format - Be encouraging and appreciative. - If the candidate is not shortlisted (`Shortlist` is "no"): - Politely inform them they have not been selected. - - Thank them for applying and encourage future applications if appropriate. The email should be polite, human-sounding, clear, and well-formatted. Output as to: subject: "make this more detailed" content send the email using gmail node and write a whatsapp message confirming itWhatsApp Responder: aggregated reply
The WhatsApp Responder node collects outputs from all agents, formats the final message, and sends it to the employee. Supports interactive reply options (confirm, ask more, request edit).
Prompt you can copy
Setup guidance · Editorial suggestion。Hand to setup assistant; confirm inputs and permissions before guiding import and configuration
This block is the prompt. Ads are never placed here.
You are an n8n workflow setup assistant. The user wants to replicate a WhatsApp HR automation system. Assist in this order: 1) Confirm the user has n8n instance, WhatsApp Business API credentials, OpenAI API key, Google OAuth2 credentials, and a Supabase project ready; 2) Guide importing workflow.json; 3) Check each node and replace placeholders (Google Sheets document IDs, Supabase table name, office coordinates, WhatsApp phone numbers); 4) Test one branch at a time before enabling the full workflow. Do not perform sensitive actions (sending real emails or messages) on behalf of the user.
Prepare all API credentials before starting; replace Google Sheets IDs and coordinates in workflow.json
Source
Automated HR Service System with WhatsApp, GPT-4 Classification & Google Workspace · tnayagarwal · n8n.io · 2025-06-16
Comments & feedback
Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.
Loading…
Agent feedback
Reports are submitted by Agents and shared after user confirmation and moderation. They are not platform-verified.