This workflow corresponds to n8n.io template #12043 — we link there as the canonical source.
This workflow follows the Gmail → Google Calendar 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": "HOUgh8szaduAUM7v",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Interview Scheduler with AI Reminders & Slack Approval",
"tags": [],
"nodes": [
{
"id": "e1e600af-68bb-40ee-9ea9-4892d3e0082e",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
0,
48
],
"parameters": {
"path": "interview-calendar-meet",
"options": {}
},
"typeVersion": 2.1
},
{
"id": "beaa4d9f-6ed1-4a4c-9e05-a3d2dcbb3be0",
"name": "Formatting the start date/time",
"type": "n8n-nodes-base.set",
"position": [
208,
48
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "37125224-1ca0-4812-abb3-0842d0afc70b",
"name": "when",
"type": "string",
"value": "={{ $json.when.marked_at }}T{{ $json.when.start_at }}:00.000-05:00"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "89edb4de-bddd-44a2-bdaf-4f80688d6d41",
"name": "Create the interview and invites the candidate",
"type": "n8n-nodes-base.googleCalendar",
"position": [
432,
48
],
"parameters": {
"end": "={{ $json.when }}",
"start": "={{ $json.when }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"additionalFields": {
"summary": "=Interview for {{ $json.vacancy }}",
"attendees": [
"={{ $json.candidate.email }}, {{ $json.participants[0].email }}"
],
"conferenceDataUi": {
"conferenceDataValues": {
"conferenceSolution": "hangoutsMeet"
}
}
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "2bd551be-0803-4913-9a12-434102de247c",
"name": "Creates the e-mail content",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
640,
48
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.o-mini",
"cachedResultName": "GPT-4.O-MINI"
},
"options": {},
"responses": {
"values": [
{
"content": "=Interview information:\n- Start time: {{ $json.start.dateTime }}\n- Name: {{ $json.summary }}\n- Interview meet URL: {{ $json.conferenceData.entryPoints[0].uri }}\n\nCandidate Information:\n- Name: {{ $('Formatting the start date/time').item.json.candidate.name }}"
},
{
"role": "system",
"content": "You are going to receive information about a video conference about a job interview from Recrutei ATS that was dated in google calendar and created a meet link.\n\nYour job is to, with all that information, create a message to remind the candidate about the interview, the e-mail will be sent 1 day before the actual day of the conference\n\nThe e-mail must be in EN-US, with a professional tone.\n\nOnly output the content of the e-mail, nothing more. Do not output a subject, only the content, without title, only the text necessary\n\nDo not sign the message."
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "4f8691e4-ba78-4f6c-bdbc-5546ad0e813e",
"name": "Separates the text",
"type": "n8n-nodes-base.set",
"position": [
992,
48
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "61ce13b2-9a7e-45d7-984e-b760ded183f9",
"name": "text",
"type": "string",
"value": "={{ $json.output[0].content[0].text }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "eb9768b8-dac9-4edc-b7d6-c057aa34dcde",
"name": "Wait until 1 day before the interview",
"type": "n8n-nodes-base.wait",
"notes": "You can personalize as you need",
"position": [
1200,
48
],
"parameters": {
"resume": "specificTime",
"dateTime": "={{ DateTime.fromISO($('Create the interview and invites the candidate').item.json.start.dateTime).minus({ days: 1 }).toISO() }}"
},
"notesInFlow": true,
"typeVersion": 1.1
},
{
"id": "882540c2-3fb0-4f16-b970-af72331e8b77",
"name": "Send the message to the candidate",
"type": "n8n-nodes-base.gmail",
"notes": "The source node of the data is specified to prevent errors.",
"position": [
1408,
48
],
"parameters": {
"sendTo": "={{ $('Formatting the start date/time').item.json.candidate.email }}",
"message": "={{ $('Separates the text').item.json.text }}",
"options": {
"senderName": "={{ $('Formatting the start date/time').item.json.participants[0].name }}",
"appendAttribution": false
},
"subject": "={{ $('Create the interview and invites the candidate').item.json.summary }}",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 2.1
},
{
"id": "fe72fa9e-ef23-4361-88fc-af7b55611e66",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-256,
-512
],
"parameters": {
"width": 1008,
"height": 400,
"content": "## Overview: AI-Powered Interview Scheduling & Reminders\n\nThis workflow automates the end-to-end process of scheduling technical or behavioral interviews. It captures interview data via Webhook, creates a Google Calendar event with an integrated Google Meet link, generates a personalized, professional reminder email using AI (GPT-4.1-mini), and automatically sends it via Gmail exactly 24 hours before the interview.\n\n## Setup Instructions\n\nTo implement this workflow, follow these steps:\n\n1. **Webhook:** Copy the Production URL and configure it in your Recrutei ATS to send interview JSON data.\n2. **Google Calendar:** Connect your account. The node is pre-configured to generate a \"hangoutsMeet\" conference link.\n3. **OpenAI:** Requires a valid API Key. The AI acts as a Recruitment Assistant to draft a professional email body.\n4. **Wait Node:** Currently set to \"1 day before\" the interview. You can adjust this timing based on your communication policy.\n5. **Gmail:** Connect your recruiter or company account to perform the final delivery.\n6. **Recrutei's API:** Inserts your Recrutei token in the Authorization header"
},
"typeVersion": 1
},
{
"id": "c45da63d-2c4a-48b7-b534-c4236af87ae6",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
-96
],
"parameters": {
"color": 7,
"width": 624,
"height": 352,
"content": "## Ingestion & Scheduling\nThe workflow triggers when candidate and vacancy details are received. A specialized Code node formats the date/time into ISO strings, ensuring Google Calendar creates the event at the correct time and generates the required video conference URL."
},
"typeVersion": 1
},
{
"id": "f03f7424-6d46-4b58-97f9-d249cda66b72",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
592,
-96
],
"parameters": {
"color": 6,
"width": 544,
"height": 352,
"content": "## AI-Driven Copywriting\nInstead of using rigid templates, the OpenAI node receives specific meeting details (candidate name, vacancy, and Meet link). It drafts a professional, humanized reminder email in English, tailoring the tone for a high-quality candidate experience."
},
"typeVersion": 1
},
{
"id": "c0186b6e-d592-4cc8-8121-f9ad1a418816",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1152,
-96
],
"parameters": {
"color": 7,
"width": 624,
"height": 352,
"content": "## Smart Delivery\nTo maximize attendance, the workflow enters a \"Wait\" state. It calculates the optimal time to send the reminder (24 hours before the session) and then automatically triggers the Gmail node to send the AI-generated content. Then, it register in the observations on the ATS."
},
"typeVersion": 1
},
{
"id": "16e3fd8f-b31f-4ee9-a574-1d63e06974bb",
"name": "Adding observation in candidate",
"type": "n8n-nodes-base.httpRequest",
"position": [
1616,
48
],
"parameters": {
"url": "https://api.recrutei.com.br/api/v2/talents-observations",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "application_id",
"value": "={{ $('Webhook').item.json.application_id }}"
},
{
"name": "talent_id",
"value": "={{ $('Webhook').item.json.id }}"
},
{
"name": "talent_observation_type_id",
"value": "7"
},
{
"name": "description",
"value": "=Candidate interview already set on Google Meet:\n{{ $('Create the interview and invites the candidate').item.json.conferenceData.entryPoints[0].uri }}"
},
{
"name": "action",
"value": "1"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer [your_token]"
},
{
"name": "Content-Type",
"value": "multipart/form-data"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "87949356-4ec5-4ba1-8789-a538aedf8030",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
1824,
48
],
"parameters": {
"resume": "specificTime",
"dateTime": "={{ $('Formatting the start date/time').item.json.when }}"
},
"typeVersion": 1.1
},
{
"id": "56924ef0-840f-4525-a925-f7a2316ffa5c",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
2240,
48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c6a61bfa-42a8-44c5-bb68-1f536c82d182",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
}
},
"executeOnce": true,
"typeVersion": 2.2
},
{
"id": "abbc00db-760d-4b51-97df-14d786c66f0b",
"name": "Adding observation in candidate1",
"type": "n8n-nodes-base.httpRequest",
"position": [
2544,
-176
],
"parameters": {
"url": "https://api.recrutei.com.br/api/v2/talents-observations",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "application_id",
"value": "={{ $('Webhook').item.json.application_id }}"
},
{
"name": "talent_id",
"value": "={{ $('Webhook').item.json.id }}"
},
{
"name": "talent_observation_type_id",
"value": "7"
},
{
"name": "description",
"value": "=Candidate was approved to proceed to the next fase!"
},
{
"name": "action",
"value": "1"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer [your_token]"
},
{
"name": "Content-Type",
"value": "multipart/form-data"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "542400b1-7e99-48b8-9535-8c0158d4288b",
"name": "Getting the vacancy",
"type": "n8n-nodes-base.httpRequest",
"position": [
2752,
-176
],
"parameters": {
"url": "=https://api.recrutei.com.br/api/v1/vacancies/{{ $('Adding observation in candidate').item.json.data.vacancy.id }}",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer [your_token]"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "847b3961-920d-4778-b3c5-4009352f6365",
"name": "Selecting pipe stage id",
"type": "n8n-nodes-base.set",
"notes": "You must personalize this as you need",
"position": [
2960,
-176
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "86700f84-3364-4d9c-a07d-bce7e5935c88",
"name": "last_stage",
"type": "number",
"value": "={{ $json.pipe_vacancy.pipe.pipe_stages[7].id }}"
}
]
}
},
"notesInFlow": true,
"typeVersion": 3.4
},
{
"id": "aa50dec9-d9f9-442b-9944-799b56d1f7ab",
"name": "Moving candidate to last stage",
"type": "n8n-nodes-base.httpRequest",
"position": [
3168,
-176
],
"parameters": {
"url": "=https://api.recrutei.com.br/api/v1/applications/{{ $('Webhook').item.json.application_id }}/pipe",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "pipe_stage_id",
"value": "={{ $json.last_stage }}"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer [your_token]"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "d7034174-e608-4e51-bdc9-d0242c648cda",
"name": "Reproval e-mail",
"type": "n8n-nodes-base.gmail",
"position": [
2544,
192
],
"parameters": {
"sendTo": "={{ $('Webhook').item.json.candidate.email }}",
"message": "=Dear {{ $('Webhook').item.json.candidate.name }},\n\nThank you very much for your interest in the {{ $('Webhook').item.json.vacancy }} position and for taking the time to participate in our selection process.\n\nAfter careful consideration, we regret to inform you that we will not be moving forward with your application at this time. Although your profile shows strong qualities, we have decided to proceed with candidates whose experience more closely matches our current needs for this role.\n\nWe wish you every success in your professional journey and thank you again for your interest in our company.\n\nKind regards",
"options": {
"appendAttribution": false
},
"subject": "={{ $('Webhook').item.json.vacancy }}",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 2.1
},
{
"id": "714fa0c8-3a49-4134-bde9-ca337a4f914c",
"name": "Request for candidate aproval",
"type": "n8n-nodes-base.slack",
"position": [
2032,
48
],
"parameters": {
"select": "channel",
"message": "=The candidate {{ $('Webhook').item.json.candidate.name }} was approved and can proceed to the next fase?",
"options": {
"limitWaitTime": {
"values": {
"resumeAmount": 4
}
}
},
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "9a8f9ee3-3a93-4e49-af05-f119fff24c1c",
"name": "Reproving candidate",
"type": "n8n-nodes-base.httpRequest",
"position": [
2752,
192
],
"parameters": {
"url": "=https://api.recrutei.com.br/api/v1/applications/rate",
"method": "PUT",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "application_id",
"value": "={{ $('Webhook').item.json.application_id }}"
},
{
"name": "rated",
"value": "0"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer [your_token]"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "f2aa7f0f-02d8-49e6-be41-d35f06708347",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1792,
-96
],
"parameters": {
"color": 6,
"width": 608,
"height": 352,
"content": "## Approving/Declining candidate\nAfter the interview, it sends a message of approval/decline in a chosen channel in Slack"
},
"typeVersion": 1
},
{
"id": "6651d5e5-3334-4a2b-89e0-598cf7c8b531",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2416,
-288
],
"parameters": {
"color": 7,
"width": 944,
"height": 320,
"content": "## Moving the candidate to the last pipe stage\nUsing the Recrutei's API, it adds an observation in the candidate informing the decision, it gets the vacancy to separate the pipe_stage_id of the last pipe stage, and then moves the candidate to the last stage"
},
"typeVersion": 1
},
{
"id": "3cfddf26-7d84-4533-80b2-569d71f16d7f",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
2416,
48
],
"parameters": {
"color": 7,
"width": 944,
"height": 368,
"content": "## Reproving candidate\nIt sends a reproval e-mail to the candidate and then creates an observation in the candidate at the ATS informing the decision"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "2747946c-f3d2-46ae-9b20-fc3bde9598e3",
"connections": {
"If": {
"main": [
[
{
"node": "Adding observation in candidate1",
"type": "main",
"index": 0
}
],
[
{
"node": "Reproval e-mail",
"type": "main",
"index": 0
}
]
]
},
"Wait": {
"main": [
[
{
"node": "Request for candidate aproval",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Formatting the start date/time",
"type": "main",
"index": 0
}
]
]
},
"Reproval e-mail": {
"main": [
[
{
"node": "Reproving candidate",
"type": "main",
"index": 0
}
]
]
},
"Separates the text": {
"main": [
[
{
"node": "Wait until 1 day before the interview",
"type": "main",
"index": 0
},
{
"node": "Send the message to the candidate",
"type": "main",
"index": 0
}
]
]
},
"Getting the vacancy": {
"main": [
[
{
"node": "Selecting pipe stage id",
"type": "main",
"index": 0
}
]
]
},
"Selecting pipe stage id": {
"main": [
[
{
"node": "Moving candidate to last stage",
"type": "main",
"index": 0
}
]
]
},
"Creates the e-mail content": {
"main": [
[
{
"node": "Separates the text",
"type": "main",
"index": 0
}
]
]
},
"Request for candidate aproval": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Formatting the start date/time": {
"main": [
[
{
"node": "Create the interview and invites the candidate",
"type": "main",
"index": 0
}
]
]
},
"Adding observation in candidate": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Adding observation in candidate1": {
"main": [
[
{
"node": "Getting the vacancy",
"type": "main",
"index": 0
}
]
]
},
"Send the message to the candidate": {
"main": [
[
{
"node": "Adding observation in candidate",
"type": "main",
"index": 0
}
]
]
},
"Wait until 1 day before the interview": {
"main": [
[
{
"node": "Send the message to the candidate",
"type": "main",
"index": 0
}
]
]
},
"Create the interview and invites the candidate": {
"main": [
[
{
"node": "Creates the e-mail content",
"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.
gmailOAuth2googleCalendarOAuth2ApiopenAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates the end-to-end process of scheduling technical or behavioral interviews. It captures interview data via Webhook, creates a Google Calendar event with an integrated Google Meet link, generates a personalized, professional reminder email using AI…
Source: https://n8n.io/workflows/12043/ — 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.
Imagine your recruitment process transformed into a sleek, efficient, AI-powered assembly line for talent. That's exactly what this system creates. It automates the heavy lifting, allowing your human
Automate your inbound lead qualification pipeline by enriching raw lead data, scoring it with AI, and instantly creating follow-up tasks for your sales team. 🎯🤖 This workflow receives new leads via we
This workflow automates the initial screening process for new job applications, freeing up your recruitment team to focus on qualified candidates. It receives applications from a webhook, uses OpenAI
This system meticulously guides each lead through a fully automated journey, from initial contact to a personalized follow-up and CRM integration.
Automate your landscaping business’s lead follow-up and booking with this AI-powered GoHighLevel workflow. Designed by Hyrum Hurst, AI Automation Engineer at QuarterSmart, this template takes every ne