Workflow to Query Events from 3 Different Google Calendars (AGENT]

Hi everyone! :waving_hand:

I’m looking for help building an n8n workflow that can query and retrieve events from 3 different Google Calendar agendas that belong to the same Google account with AI Agent.

I pay for this help

What I’m trying to achieve:

  • Connect to my Google account (already have the credentials set up)
  • Query events from 3 specific calendars/agendas within that account
  • Retrieve events within a specific date range
  • Ideally combine or process the results from all 3 calendars

Current challenges:

  • Not sure how to specify different calendar IDs in the Google Calendar node
  • Wondering if I need multiple Google Calendar nodes or if there’s a way to loop through different calendars
  • Need guidance on how to handle the different calendar responses and potentially merge them

Technical details:

  • n8n version: [please specify your version]
  • Google Calendar node: Already configured with OAuth2
  • Expected output: Events from all 3 calendars, preferably with calendar source identification

Questions:

  1. What’s the best approach to query multiple calendars from the same Google account?
  2. Should I use multiple Google Calendar nodes or implement a loop?
  3. How can I identify which calendar each event comes from in the final output?
  4. Any tips for handling rate limits when querying multiple calendars?

Has anyone built something similar? I’d really appreciate any workflow examples, screenshots, or guidance you can share!

Thanks in advance! :folded_hands:


Tags: google-calendar #workflow #multiple-calendars #help-needed

Hi, using one calender node is possible. A loop node isn’t needed for this. As it automatically loops for the amount of items from the node before.

If you for example had a node (before the calender node) that outputted 3 items, with the id of each calender. You could inside the node add a expression. Which would make it run a unique id for each item.

You could also just add 3 nodes and use merge node like this:

With Agent ai, is it possible ?

Something like this?

Only need to select the calendar here and attach 3 calendar node with get many

I tried this way but for some reason it doesn’t consider the other accounts, only the first one and it returns that there is already an appointment at that time, while account 2 and 3 are free to book.

Can you share what’s your prompt ?

{
“name”: “cris_pet_shop”,
“nodes”: [
{
“parameters”: {
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.chatTrigger”,
“typeVersion”: 1.1,
“position”: [
-260,
100
],
“id”: “1899ec03-e730-4a45-9b10-3abed60364a3”,
“name”: “When chat message received”,
“webhookId”: “fdc4b18a-9649-4724-92ad-24d771e00ed9”
},
{
“parameters”: {
“options”: {
“systemMessage”: “=Você é uma atendente virtual de um pet shop, e seu papel é agendar banhos para os pets dos clientes, utilizando os calendários do Google das funcionárias disponíveis.\n\n## Variáveis Úteis\n- Data de hoje:\n {{ $now.format(‘yyyy-MM-dd’)}} | {{ $now.weekdayLong }}\n\n- Data de amanhã:\n {{ $now.plus(1,‘day’).format(‘yyyy-MM-dd’)}} | {{ $now.plus(1,‘day’).weekdayLong }}\n- Hora atual:\n {{ $now.format(‘HH:mm:ss’)}}\n\n👩‍💼 Funcionárias disponíveis para agendamento:\nMarina\n\nAnita\n\nLarisa\n\n⚠️ REGRA CRÍTICA – USO DA DATA E VERIFICAÇÃO DE AGENDA\nAntes de qualquer verificação de agenda, você deve obrigatoriamente usar a ferramenta:\n\n## Exemplos\n\n### Exemplo de Título de Evento:\nCliente Marina Silva | Suporte Técnico\n\n## Regras Importantes\n- Não mencione o ano, pois todos os agendamentos serão no mesmo ano\n- Liste os horários apenas com números e a palavra ‘horas’ no final, exemplo: 8, 9, 21 horas \n- Responda de forma simples, educada e direta\n- Ao listar horários, site no máximo 3, exemplo: – Temos 15 e 18 horas\n- Nunca crie um valores para os campos email, ID ou iCalUID. Utilize apenas os valores fornecidos na lista\nde profissionais.\n- O título do evento deve conter o nome do cliente e o nome da equipe ou profissional.\n Exemplo: Cliente Joaquim | Equipe de Vendas\n- Nunca mostre dados de contato (telefone ou e-mail) dos profissionais.\n- Antes de agendar um horário, sempre consulte a disponibilidade do profissional (via list_slots com o iCalUID).\n- Nunca utilize o telefone ou e-mail do profissional para cancelar eventos.\n\n### :repeat_button: Para atualizar um agendamento existente:\n1. Liste todos os eventos do cliente pelo telefone ou e-mail informado.\n2. Localize o event_id correspondente.\n3. Verifique os horários disponíveis (slots) para a nova data.\n4. Pergunte o novo horário desejado.\n5. Atualize o evento usando o id do evento.\n :warning: O formato do id é semelhante a: oeinnvtgfsrutk57ttghg55tr8\n\n### :cross_mark: Para cancelar apenas um agendamento de um cliente:\n1. Liste todos os eventos do cliente pelo telefone informado.\n2. Localize o id correspondente ao evento que será cancelado.\n3. Localize o iCalUID correspondente ao profissional do evento que será cancelado.\n 'delete_only_events’iCalUID\n\n### :cross_mark: Para cancelar todos os agendamentos de um cliente:\n1. Use a ferramenta ‘delete_all_events’\n2. Passe como parâmentro o telefone e email do cliente.\n :warning: Não use e-mail ou telefone do profissional para cancelar.\n\n\n\nIsso garante que o sistema interprete corretamente as consultas aos calendários do Google.\n\n​:brain: Lógica para identificar horário vago:\nApós a consulta usando as ferramentas:\n\npet_agenda_marina_agendar_verificar\n\npet_agenda_anita_agendar_verificar\n\npet_agenda_larisa_agendar_verificar\n\nA resposta virá em um formato semelhante a:\n[\n {\n "Return_All": true,\n "After": "2025-05-30T15:30:00-03:00",\n "Before": "2025-05-30T16:00:00-03:00"\n }\n]\n\n​:white_check_mark: Se não houver nenhum agendamento listado dentro desse intervalo, então o horário está livre e pode ser agendado normalmente.\n\n​:dog_face: Fluxo da Conversa:\nCumprimente o cliente com simpatia.\n\nPergunte a raça do pet para calcular o tempo necessário:\n\n​:one_o_clock: 1 hora:\n\nSão Bernardo\n\nFila Brasileiro\n\nPastor Alemão\n\nLabrador\n\n​:twelve_thirty: 30 minutos:\n\nYorkshire Terrier\n\nChihuahua\n\nPinscher\n\n​:dog: Outras raças: padrão de 30 minutos\n\nPergunte a data e horário desejado.\n\nChame a ferramenta data_hora e só então consulte as agendas.\n\nConsulte as agendas das funcionárias com base no tempo necessário.\n\nSe mais de uma agenda estiver disponível, escolha aleatoriamente entre elas.\n\nApós escolher o horário e a funcionária, peça os dados do cliente um por vez:\n\nNome\n\nE-mail\n\nTelefone\n\nEndereço\n\nFaça o agendamento na agenda da profissional usando:\n\npet_agenda_marina_agendar\n\npet_agenda_anita_agendar\n\npet_agenda_larisa_agendar\n\nAdicione automaticamente 20 minutos ao final do agendamento para a limpeza do ambiente.\n​:warning: Não informe isso ao cliente.\n\n​:hugs: Finalização:\nConfirme com o cliente o horário e a funcionária.\n\nAgradeça com carinho e diga que o pet será muito bem cuidado.\n\nFinalize oferecendo ajuda para outras dúvidas ou reagendamentos.\n\n”
}
},
“type”: “@n8n/n8n-nodes-langchain.agent”,
“typeVersion”: 2,
“position”: [
352,
100
],
“id”: “775277d3-84e0-4b11-922e-a59d3591351b”,
“name”: “AI Agent”
},
{
“parameters”: {
“calendar”: {
“__rl”: true,
“value”: “d641e4b22358ca9e306e291bf0d788aa9e8bd8d5ca1f3ee7165eca36882d78ee@group.calendar.google.com”,
“mode”: “list”,
“cachedResultName”: “pet_agenda_marina”
},
“start”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Start’, , 'string') }}", "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', , ‘string’) }}”,
“additionalFields”: {
“description”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Description’, , 'string') }}" } }, "type": "n8n-nodes-base.googleCalendarTool", "typeVersion": 1.3, "position": [ 140, 320 ], "id": "85e1e6be-1e50-4076-92c0-f9b1d3588748", "name": "pet_agenda_marina_agendar", "credentials": { "googleCalendarOAuth2Api": { "id": "WkR1GB3kWFVkWzNh", "name": "Google Calendar account" } } }, { "parameters": { "operation": "getAll", "calendar": { "__rl": true, "value": "d641e4b22358ca9e306e291bf0d788aa9e8bd8d5ca1f3ee7165eca36882d78ee@group.calendar.google.com", "mode": "list", "cachedResultName": "pet_agenda_marina" }, "returnAll": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Return_All', , ‘boolean’) }}”,
“timeMin”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘After’, , 'string') }}", "timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Before', , ‘string’) }}”,
“options”: {}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
300,
320
],
“id”: “78146b88-33a1-4595-b69b-2beef471782f”,
“name”: “pet_agenda_marina_agendar_verificar”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “WkR1GB3kWFVkWzNh”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“operation”: “getAll”,
“calendar”: {
“__rl”: true,
“value”: “aa750b2ee43d900ded76c1433eae364e73e714376fedd5017843f089e7d5c91e@group.calendar.google.com”,
“mode”: “list”,
“cachedResultName”: “pet_agenda_anita”
},
“returnAll”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Return_All’, , 'boolean') }}", "timeMin": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('After', , ‘string’) }}”,
“timeMax”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Before’, , 'string') }}", "options": {} }, "type": "n8n-nodes-base.googleCalendarTool", "typeVersion": 1.3, "position": [ 460, 320 ], "id": "640efefc-9a2b-47ce-a165-61321d6d038c", "name": "pet_agenda_anita_agendar_verificar", "credentials": { "googleCalendarOAuth2Api": { "id": "WkR1GB3kWFVkWzNh", "name": "Google Calendar account" } } }, { "parameters": { "calendar": { "__rl": true, "value": "aa750b2ee43d900ded76c1433eae364e73e714376fedd5017843f089e7d5c91e@group.calendar.google.com", "mode": "list", "cachedResultName": "pet_agenda_anita" }, "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', , ‘string’) }}”,
“end”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘End’, , 'string') }}", "additionalFields": { "description": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Description', , ‘string’) }}”
}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
560,
320
],
“id”: “56d3acc6-62ac-4c32-9e0e-0d0be8dae3cc”,
“name”: “pet_agenda_anita_agendar”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “WkR1GB3kWFVkWzNh”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“calendar”: {
“__rl”: true,
“value”: “c70bf98c9a4215aaca6d397fefdefe39475af60887555eb376394321eb0c7061@group.calendar.google.com”,
“mode”: “list”,
“cachedResultName”: “pet_agenda_larisa”
},
“start”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Start’, , 'string') }}", "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', , ‘string’) }}”,
“additionalFields”: {
“description”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Description’, , 'string') }}" } }, "type": "n8n-nodes-base.googleCalendarTool", "typeVersion": 1.3, "position": [ 680, 320 ], "id": "8474f19e-5b42-4d99-88c6-98d977a7e6bc", "name": "pet_agenda_anita_agendar1", "credentials": { "googleCalendarOAuth2Api": { "id": "WkR1GB3kWFVkWzNh", "name": "Google Calendar account" } } }, { "parameters": { "operation": "getAll", "calendar": { "__rl": true, "value": "aa750b2ee43d900ded76c1433eae364e73e714376fedd5017843f089e7d5c91e@group.calendar.google.com", "mode": "list", "cachedResultName": "pet_agenda_anita" }, "returnAll": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Return_All', , ‘boolean’) }}”,
“timeMin”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘After’, , 'string') }}", "timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Before', , ‘string’) }}”,
“options”: {}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
800,
320
],
“id”: “b070d613-c9b5-4bab-aee5-e194ebc63d5d”,
“name”: “pet_agenda_larisa_agendar_verificar”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “WkR1GB3kWFVkWzNh”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“model”: {
“__rl”: true,
“mode”: “list”,
“value”: “gpt-4o-mini”
},
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.lmChatOpenAi”,
“typeVersion”: 1.2,
“position”: [
-220,
320
],
“id”: “b6354930-b333-4fd0-acc4-8342868953ac”,
“name”: “OpenAI Chat Model”,
“credentials”: {
“openAiApi”: {
“id”: “ElrefuJuXJpjsXz7”,
“name”: “OpenAi 360house”
}
}
},
{
“parameters”: {
“options”: {}
},
“type”: “n8n-nodes-base.dateTimeTool”,
“typeVersion”: 2,
“position”: [
920,
320
],
“id”: “089ba85c-edc2-427a-9a52-ca8a13b2e657”,
“name”: “data_hora”
},
{
“parameters”: {
“options”: {
“includeInputFields”: true,
“timezone”: “America/Sao_Paulo”
}
},
“type”: “n8n-nodes-base.dateTime”,
“typeVersion”: 2,
“position”: [
-260,
-260
],
“id”: “b0572fbe-fc63-4ccf-b381-2dfd1ca04da4”,
“name”: “Date & Time”
},
{
“parameters”: {
“assignments”: {
“assignments”: [
{
“id”: “5f40ad92-6ae3-4687-a0d2-a82db08070cc”,
“name”: “chatInput”,
“value”: “={{ $json.chatInput }}”,
“type”: “string”
},
{
“id”: “b4f465a0-4144-4d75-a2b7-c63faa0b6fe6”,
“name”: “currentDate”,
“value”: “={{ $json.currentDate }}”,
“type”: “string”
}
]
},
“options”: {}
},
“type”: “n8n-nodes-base.set”,
“typeVersion”: 3.4,
“position”: [
-40,
-260
],
“id”: “9a24d86b-13c9-429f-a008-77f5b4688d80”,
“name”: “base”
},
{
“parameters”: {
“contextWindowLength”: 20
},
“type”: “@n8n/n8n-nodes-langchain.memoryBufferWindow”,
“typeVersion”: 1.3,
“position”: [
-40,
320
],
“id”: “c17ddff9-22af-49be-b5e6-c85b396c8550”,
“name”: “Simple Memory”
}
],
“pinData”: {},
“connections”: {
“When chat message received”: {
“main”: [
[
{
“node”: “AI Agent”,
“type”: “main”,
“index”: 0
}
]
]
},
“pet_agenda_marina_agendar”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“pet_agenda_marina_agendar_verificar”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“pet_agenda_anita_agendar_verificar”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“pet_agenda_anita_agendar”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“pet_agenda_anita_agendar1”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“pet_agenda_larisa_agendar_verificar”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“OpenAI Chat Model”: {
“ai_languageModel”: [
[
{
“node”: “AI Agent”,
“type”: “ai_languageModel”,
“index”: 0
}
]
]
},
“data_hora”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“Date & Time”: {
“main”: [
[
{
“node”: “base”,
“type”: “main”,
“index”: 0
}
]
]
},
“base”: {
“main”: [

]
},
“Simple Memory”: {
“ai_memory”: [
[
{
“node”: “AI Agent”,
“type”: “ai_memory”,
“index”: 0
}
]
]
}
},
“active”: false,
“settings”: {
“executionOrder”: “v1”
},
“versionId”: “11b2a1f9-91c9-4c05-8e09-d52999acbf8d”,
“meta”: {
“templateCredsSetupCompleted”: true,
“instanceId”: “7bd9673c4ccbbb27c93e1f0a43d58ddb9ad75183485808a0b34afe3c5b4737a2”
},
“id”: “f0egafAvQFyujHEr”,
“tags”:
}

I wouldn’t recommend using the AI agent for this purpose. If you needed the AI agent to pick the calender node. It would work. But if you want it to get all events everytime for all 3. It’s best make it run as standalone nodes.

The reason being because of how the AI agent works. It’s basically deciding when to use the tool. You could probably specify in the prompt to always use the tools. But I wouldn’t trust it in a production workflow.

There are some possible reasons.

  1. add the prompt force AI to check every calendar.
⚠️ Regra obrigatória:
Antes de sugerir qualquer horário ao cliente, você deve obrigatoriamente consultar a agenda das três funcionárias: Marina, Anita e Larisa.

Use as ferramentas:
- pet_agenda_marina_agendar_verificar
- pet_agenda_anita_agendar_verificar
- pet_agenda_larisa_agendar_verificar

Você só pode considerar um horário como disponível se todas as agendas forem verificadas.
  1. SInce your prompt is quite long. Considering use 4.1-mini to see if the result will be better. The API price is slightly higher than 4o-mini

price:
4o-mini , 4.1-mini
$0.15 , $0.40 → input
$0.60 , $1.60 → output