I have a problem with Google Calendar

I have an automation that, as its final step, is supposed to schedule an appointment via Google Calendar, but it’s not working correctly. The AI ​​agent asks when it wants the appointment, but it schedules it for October, and when it schedules for right now, it doesn’t respect the 30-minute duration; instead, it schedules it for a full hour. It also doesn’t include the specified title, and on top of that, I have to send it another message after I’ve already sent the appointment confirmation just to get it to respond. I’ve been stuck in a loop for hours.
I’ve attached the JSON file in case anyone can help.

Describe the problem/error/question

What is the error message (if any)?

Please share your workflow

	
name	"Evolution API Whatsapp Chatbot for Jordi Fluency Leads CALENDAR DEF (PRUEBAS)"
nodes	
0	
parameters	
httpMethod	"POST"
path	"whatsapp"
options	{}
type	"n8n-nodes-base.webhook"
typeVersion	2.1
position	
0	-2416
1	64
id	"fd108c05-8d9a-413d-9190-b552d60a2fcd"
name	"Webhook"
webhookId	"5f5a8b82-e018-480a-a88d-972ee080e6f8"
1	
parameters	
method	"POST"
url	"http://srv1267323.hstgr.cloud:8080/message/sendText/inmobiliaria"
sendHeaders	true
headerParameters	
parameters	
0	
name	"apikey"
value	"cwffZbOX02vrDZB4kBc8BQXhCdMlcD4D"
sendBody	true
specifyBody	"json"
jsonBody	`={\n  "number": "{{ $('Webhook').item.json.body.data.key.remoteJid.replace('@s.whatsapp.net', '') }}",\n  "text": "{{ $('AI Agent').item.json.output }}",\n  "linkPreview": false\n}`
options	{}
type	"n8n-nodes-base.httpRequest"
typeVersion	4.3
position	
0	-944
1	96
id	"e565afe9-8d25-46c8-aa20-1b6bbc61f50d"
name	"HTTP Request"
2	
parameters	
rules	
values	
0	
conditions	
options	{…}
conditions	[…]
combinator	"and"
renameOutput	true
outputKey	"Text"
1	
conditions	
options	{…}
conditions	[…]
combinator	"and"
renameOutput	true
outputKey	"Text With Link"
2	
conditions	
options	{…}
conditions	[…]
combinator	"and"
renameOutput	true
outputKey	"Audio"
3	
conditions	
options	{…}
conditions	[…]
combinator	"and"
renameOutput	true
outputKey	"Image"
options	{}
type	"n8n-nodes-base.switch"
typeVersion	3.4
position	
0	-2016
1	48
id	"dac7bc13-d685-43ae-b1ff-165df73c8244"
name	"Switch"
3	
parameters	
method	"POST"
url	"http://srv1267323.hstgr.cloud:8080/chat/getBase64FromMediaMessage/inmobiliaria"
sendHeaders	true
headerParameters	
parameters	
0	
name	"apikey"
value	"cwffZbOX02vrDZB4kBc8BQXhCdMlcD4D"
sendBody	true
specifyBody	"json"
jsonBody	'={{\n  {\n    "message": $json.body.data,\n    "convertToMp4": false\n  }\n}}'
options	{}
type	"n8n-nodes-base.httpRequest"
typeVersion	4.3
position	
0	-1728
1	-144
id	"57f92dca-d79c-4dd1-9a76-f07fd8d4bb46"
name	"Download Audio"
4	
parameters	
operation	"toBinary"
sourceProperty	"base64"
options	
fileName	"voice_note.ogg"
type	"n8n-nodes-base.convertToFile"
typeVersion	1.1
position	
0	-1536
1	-144
id	"61261ba5-c5c2-4b78-a020-61a565206540"
name	"Convert to File"
5	
parameters	
resource	"audio"
operation	"transcribe"
options	{}
type	"@n8n/n8n-nodes-langchain.openAi"
typeVersion	2.1
position	
0	-1344
1	-144
id	"e84064b0-5f2d-4b14-ad53-a5897d2f4c28"
name	"Transcribe a recording"
credentials	
openAiApi	
id	"ayMsi7sUQnOVm40G"
name	"OpenAi account"
6	
parameters	
promptType	"define"
text	"FECHA ACTUAL DEL SISTEMA: {{ $now.toFormat('yyyy-MM-dd HH:mm') }} (Hoy es domingo 8 de Febrero de 2026). Mensaje del usuario: {{ $json.mensaje }}"
options	
systemMessage	`### ROLE\nEres el Asistente de Inmobiliaria Mora. Tu tono es profesional, breve y directo.\n\n### CONTEXTO TEMPORAL\n- Hoy es: {{ $now.toFormat('cccc, dd LLLL yyyy') }}.\n- ESTAMOS EN FEBRERO DE 2026. Ignora cualquier mensaje antiguo sobre "octubre".\n\n### OBJETIVO\n1. Cualifica (Hipoteca, Tipo, Zona, Presupuesto) uno a uno.\n2. Al tener los 4, pide fecha y hora.\n3. CUANDO TE DEN FECHA Y HORA:\n   - USA la herramienta Google Calendar inmediatamente.\n   - Start Time: La fecha/hora del usuario.\n   - End Time: 30 minutos exactos después del inicio.\n   - Summary: "Visita Inmobiliaria - Lead"\n   - MUY IMPORTANTE: n8n espera que des una respuesta final después de usar la herramienta. Una vez agendado, DEBES generar un mensaje de texto confirmando: "¡Perfecto! Cita confirmada para el [DIA] a las [HORA]. ¡Nos vemos!". \n\n### RESTRICCIONES\n- No digas que "no tienes acceso" o "no puedes ver disponibilidad". Simplemente agenda.\n- No pidas confirmación para agendar, hazlo directamente cuando te den la hora.`
type	"@n8n/n8n-nodes-langchain.agent"
typeVersion	3.1
position	
0	-1456
1	96
id	"12d1917d-93c7-4a51-919d-78a25d7d4c60"
name	"AI Agent"
7	
parameters	
model	
__rl	true
value	"gpt-4o-mini"
mode	"list"
cachedResultName	"gpt-4o-mini"
builtInTools	{}
options	{}
type	"@n8n/n8n-nodes-langchain.lmChatOpenAi"
typeVersion	1.3
position	
0	-1456
1	272
id	"f4998898-9fc9-48db-a0f0-82065e40cec0"
name	"OpenAI Chat Model"
credentials	
openAiApi	
id	"ayMsi7sUQnOVm40G"
name	"OpenAi account"
8	
parameters	
sessionIdType	"customKey"
sessionKey	"={{ $('Webhook').item.json.body.data.key.remoteJid }}_v2"
contextWindowLength	10
type	"@n8n/n8n-nodes-langchain.memoryBufferWindow"
typeVersion	1.3
position	
0	-1296
1	384
id	"a5b2a1f5-fcc3-4903-8e68-ce004a5f9125"
name	"Simple Memory"
9	
parameters	
modelId	
__rl	true
value	"gpt-4o-mini"
mode	"list"
cachedResultName	"GPT-4O-MINI"
responses	
values	
0	
type	"image"
imageType	"base64"
1	
content	"Describe this real estate image in 1 sentence. Is it a room, a house, or a document?"
builtInTools	{}
options	{}
type	"@n8n/n8n-nodes-langchain.openAi"
typeVersion	2.1
position	
0	-1568
1	448
id	"0ffd8a73-c30c-45a3-959a-43619ff8dd3a"
name	"Message a model"
credentials	
openAiApi	
id	"ayMsi7sUQnOVm40G"
name	"OpenAi account"
10	
parameters	
jsCode	"// 1. Get the raw image data (Base64) from the Webhook\nconst base64 = items[0].json.body.data.message.base64 || items[0].json.body.base64;\n\n// 2. Create the file package for OpenAI\nreturn [\n  {\n    json: { success: true },\n    binary: {\n      data: {\n        data: base64,\n        mimeType: 'image/jpeg',\n        fileExtension: 'jpg',\n        fileName: 'house.jpg'\n      }\n    }\n  }\n];"
type	"n8n-nodes-base.code"
typeVersion	2
position	
0	-1808
1	448
id	"659ce590-db35-4dba-8029-b4df2044159e"
name	"Code in JavaScript"
11	
parameters	
jsCode	`const data = $input.item.json;\n\n// 1. IMAGE RESULT (Check all possible output names)\n// It usually comes in 'response', 'output', or 'content'\nconst imageText = data.response || data.output || data.content || (data.message ? data.message.content : null);\n\n// 2. AUDIO RESULT (Transcription)\nconst audioText = data.text;\n\n// 3. WHATSAPP TEXT (Standard & Links)\n// We use ?. to safely dig into the nested structure without crashing\nconst waText = data.body?.data?.message?.conversation || data.body?.data?.message?.extendedTextMessage?.text;\n\n// OUTPUT: Create one single "chatInput" for the AI Agent\nreturn {\n  chatInput: imageText || audioText || waText || "User sent a file without text"\n};`
type	"n8n-nodes-base.code"
typeVersion	2
position	
0	-1696
1	96
id	"89962125-10e5-4101-80bd-c02141c502fa"
name	"Code in JavaScript1"
12	
parameters	
descriptionType	"manual"
toolDescription	"Create an event in Google Calendar. \nUse this tool to schedule a meeting. You must provide a start time, end time, and a summary (name of the client)."
calendar	
__rl	true
value	"[email protected]"
mode	"list"
cachedResultName	"[email protected]"
start	"="
end	"="
additionalFields	
summary	"="
type	"n8n-nodes-base.googleCalendarTool"
typeVersion	1.3
position	
0	-1152
1	384
id	"47636df4-a806-4834-ae6f-7912ebfe37c1"
name	"Create an event in Google Calendar"
credentials	
googleCalendarOAuth2Api	
id	"gf1PReFlu0pAZftJ"
name	"Google Calendar account"
13	
parameters	
conditions	
options	
caseSensitive	true
leftValue	""
typeValidation	"strict"
version	3
conditions	
0	
id	"c0aefbd9-a206-476d-aa3a-07736751aded"
leftValue	"={{ $json.body.data.key.fromMe }}"
rightValue	true
operator	
type	"boolean"
operation	"equals"
combinator	"and"
options	{}
type	"n8n-nodes-base.if"
typeVersion	2.3
position	
0	-2240
1	64
id	"4e503726-c7fa-458d-a657-a77fa798614a"
name	"If"
pinData	{}
connections	
Webhook	
main	
0	
0	
node	"If"
type	"main"
index	0
Switch	
main	
0	
0	
node	"Code in JavaScript1"
type	"main"
index	0
1	
0	
node	"Code in JavaScript1"
type	"main"
index	0
2	
0	
node	"Download Audio"
type	"main"
index	0
3	
0	
node	"Code in JavaScript"
type	"main"
index	0
Download Audio	
main	
0	
0	
node	"Convert to File"
type	"main"
index	0
Convert to File	
main	
0	
0	
node	"Transcribe a recording"
type	"main"
index	0
Transcribe a recording	
main	
0	
0	
node	"Code in JavaScript1"
type	"main"
index	0
OpenAI Chat Model	
ai_languageModel	
0	
0	
node	"AI Agent"
type	"ai_languageModel"
index	0
Simple Memory	
ai_memory	
0	
0	
node	"AI Agent"
type	"ai_memory"
index	0
AI Agent	
main	
0	
0	
node	"HTTP Request"
type	"main"
index	0
Message a model	
main	
0	
0	
node	"Code in JavaScript1"
type	"main"
index	0
Code in JavaScript	
main	
0	
0	
node	"Message a model"
type	"main"
index	0
Code in JavaScript1	
main	
0	
0	
node	"AI Agent"
type	"main"
index	0
Create an event in Google Calendar	
ai_tool	
0	
0	
node	"AI Agent"
type	"ai_tool"
index	0
If	
main	
0	[]
1	
0	
node	"Switch"
type	"main"
index	0
active	false
settings	
executionOrder	"v1"
availableInMCP	false
versionId	"e4e74e94-ca5a-45c2-82ab-7bfdf91de9ee"
meta	
instanceId	"7631c1cf1a7fa8301b8f630136749c6d300c03b970dc38b63e74eaa94cdb615c"
id	"XQMa7llRd-IueFT54bW6N"
tags	[]

Share the output returned by the last node

Information on your n8n setup

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hey @Jordi_Mora the AI is likely misinterpreting relative dates. Fix this by:

Add a Code node before Google Calendar to parse and validate dates:

// Get the AI's scheduled time
const scheduledTime = $input.item.json.scheduledTime;
const now = new Date();

// Parse the date string the AI provides
let eventDate = new Date(scheduledTime);

// If date is in the past or wrong month, default to "now + 1 hour"
if (eventDate < now || eventDate.getMonth() !== now.getMonth()) {
  eventDate = new Date(now.getTime() + 60 * 60 * 1000); // 1 hour from now
}

// Calculate end time (30 minutes later)
const endDate = new Date(eventDate.getTime() + 30 * 60 * 1000);

return {
  json: {
    startTime: eventDate.toISOString(),
    endTime: endDate.toISOString(),
    title: $input.item.json.title || "Appointment",
    description: $input.item.json.description || ""
  }
};

2. Duration Issue (1 hour instead of 30 minutes)

In your Google Calendar node:

  • Make sure you’re setting both Start and End times

  • Use the Code node output above for precise timing

  • Set End Time as: {{ $json.endTime }}

3. Missing Title

In your AI Agent’s system prompt, add explicit instructions:

When scheduling appointments, you MUST extract and provide:
1. title: The appointment title/subject
2. scheduledTime: The exact date and time in ISO format (YYYY-MM-DDTHH:mm:ss)
3. description: Any additional details

Example output format:
{
  "title": "Client Meeting",
  "scheduledTime": "2024-01-15T14:30:00",
  "description": "Discussion about property"
}

4. Needing Extra Message to Get Response

This suggests the agent isn’t responding after the calendar action. Fix by:

Add a final response node after Google Calendar:

  1. Add an AI Agent or Send Message node after calendar creation

  2. Configure it to send confirmation back to WhatsApp:

Appointment confirmed! 
📅 {{ $json.title }}
🕐 {{ $json.startTime }}
⏱️ Duration: 30 minutes

Recommended Workflow Structure

Webhook (WhatsApp) 
  → AI Agent (extract appointment details)
  → Code (validate & format dates)
  → Google Calendar (create event)
  → Send WhatsApp Response (confirmation)
1 Like

Hi @Jordi_Mora, welcome to the n8n community! From what I see in your setup, the agent is choosing start, end, duration, and summary, which causes wrong dates, default one hour events, and missing titles. What works reliably for me is letting the agent only extract the date and time as text and handling all date logic in the workflow. I calculate the end time in code, for example start plus exactly 30 minutes, and pass start, end, and summary explicitly to the Google Calendar node. My rule of thumb is that LLMs are not reliable when it comes to time logic. :wink:

Hi @Jordi_Mora Welcome!
This kind of problem is usually just about the system prompt you have given and the corresponding AI prompt, just tailor those to your context very strictly and things should start working just fine, and clearly specify your context, dates & objective and this would work, sharing your workflow configurations would help us more, hope this helps.

This usually happens because contacts export/import only brings basic contact fields. Notes, tasks, conversations, workflow history, payments, and activity logs do not migrate between agencies. HighLevel doesn’t support a full data merge or historical transfer. The only way to preserve everything is moving the sub-account via agency transfer, not export/import. If you want, I can walk you through the cleanest way to handle this without losing critical data: Calendly - AKINLOLU ABDULMUQEET