Hi everyone,
I’m struggling with a workflow using a Protected Webhook in n8n.
Setup:
- Webhook: Protected Webhook (POST)
- AI Agent node with Google Calendar tools:
- Get many events
- Get an event
- Create an event
- Goal: Automatically create a calendar event when all required fields are present
Problem:
- The workflow works perfectly when using the TEST webhook URL
- When switching to the PROTECTED webhook URL:
- Webhook node turns green
- AI Agent runs and responds
- BUT: Google Calendar tools are NOT executed
- Execution log shows: “None of your tools were used in this run”
- No event is created in Google Calendar
What I already checked:
- Data arrives correctly (POST JSON body)
- Required fields are present (name, reason, date, time, contact)
- Same workflow, same prompt, same data
- Only difference is Test URL vs Protected URL
Question:
Is there a known limitation where Protected Webhooks prevent AI Agents from executing tools?
If so, what is the recommended way to keep security while allowing tool execution?
Thanks a lot for your help!
{
“name”: “My workflow”,
“nodes”: [
{
“parameters”: {
“httpMethod”: “POST”,
“path”: “62611869-7ec9-4111-8c89-4073c5625557”,
“responseMode”: “responseNode”,
“options”: {}
},
“type”: “n8n-nodes-base.webhook”,
“typeVersion”: 2.1,
“position”: [
0,
0
],
“id”: “edbd0948-dfb5-4570-bc0a-78d2873d1227”,
“name”: “Webhook”,
“webhookId”: “62611869-7ec9-4111-8c89-4073c5625557”
},
{
“parameters”: {
“promptType”: “define”,
“text”: “=Die folgenden Daten stammen aus einem Webhook-Request\nund beschreiben einen gewünschten Patiententermin.\n\nAnalysiere die Webhook-Daten vollständig.\n\nSobald alle Pflichtfelder vorhanden sind\nVollständiger Name,{{ $json.query[‘Vollständiger Name’] }}\nTelefonnummer oder E-Mail,{{ $json.query[‘Telefonnummer oder E-Mail’] }}\nGrund des Termins, {{ $json.query[‘Grund des Termins (z. B. Zahnschmerzen)’] }}\nWunschtermin (Datum),{{ $json.query[‘Wunschtermin (Datum)’] }}\nWunschzeit{{ $json.query.Wunschzeit }}\nund der Termin im Google Kalender verfügbar ist,\n\nMUSST du zwingend das Tool „Create Event“ aufrufen\nund den Termin im Google Kalender erstellen.\n\nAntworte nicht nur mit Text.\nErstelle in diesem Fall immer den Kalendereintrag.\n”,
“options”: {
“systemMessage”: “Du bist ein AI-Assistent für eine Arztpraxis.\n\nDeine Hauptaufgabe ist es, Patiententermine im Google Kalender zu verwalten.\nJeder Kalendereintrag entspricht genau einem Patiententermin.\nDer Kalender stellt die Verfügbarkeit der Arztpraxis dar.\n\nDu kannst:\n- neue Patiententermine im Kalender erstellen\n- bestehende Termine anzeigen\n- Termine ändern oder verschieben\n- Termine vollständig stornieren\n\nBei jeder Anfrage prüfst du zuerst,\nob der gewünschte Termin im Kalender verfügbar ist,\num Überschneidungen und Doppelbuchungen zu vermeiden.\n\n—\n\nAUTOMATISCHE TERMINERSTELLUNG (WICHTIG):\n\nWenn alle erforderlichen Informationen vorhanden sind\n(Name des Patienten, Kontaktmöglichkeit, Datum, Uhrzeit, Grund des Termins)\nUND der gewünschte Termin im Kalender verfügbar ist,\ndann erstellst du den Termin AUTOMATISCH im Kalender,\nohne eine zusätzliche Bestätigung anzufordern.\n\n—\n\nFalls Informationen fehlen\n(z. B. Datum, Uhrzeit oder Name),\nfrage gezielt danach, bevor du ein Tool verwendest.\n\nFalls mehrere Termine ähnlich sind,\nstelle Rückfragen, um den richtigen Termin eindeutig zu identifizieren.\n\n—\n\nDir stehen folgende Tools zur Verfügung:\n\n- Create Event \n → erstelle einen neuen Patiententermin im Kalender\n\n- Get Many Events \n → zeige aktuelle oder kommende Termine an\n (Übersicht inkl. Event-IDs)\n\n- Get an Event \n → rufe detaillierte Informationen zu einem einzelnen Termin ab\n\n- Update Event \n → ändere einen bestehenden Patiententermin\n (z. B. Datum oder Uhrzeit verschieben)\n\n- Delete Event \n → storniere einen bestehenden Patiententermin vollständig\n\n—\n\nAntworte immer:\n- ruhig\n- klar\n- freundlich\n- professionell\n\nDeine Kommunikation soll effizient,\nmedizinisch neutral\nund lösungsorientiert sein.\n”
}
},
“type”: “@n8n/n8n-nodes-langchain.agent”,
“typeVersion”: 3,
“position”: [
536,
0
],
“id”: “6b0fbf72-e53f-49a8-a95f-4368a2b4da34”,
“name”: “AI Agent”
},
{
“parameters”: {
“model”: {
“__rl”: true,
“mode”: “list”,
“value”: “gpt-4.1-mini”
},
“builtInTools”: {},
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.lmChatOpenAi”,
“typeVersion”: 1.3,
“position”: [
224,
224
],
“id”: “c1458897-06dc-41a1-99ba-c7f6404682fc”,
“name”: “OpenAI Chat Model”,
“credentials”: {
“openAiApi”: {
“id”: “OSjX3tyrhAomo4d5”,
“name”: “OpenAi account”
}
}
},
{
“parameters”: {
“sessionIdType”: “customKey”,
“sessionKey”: “={{ $json.query }}”
},
“type”: “@n8n/n8n-nodes-langchain.memoryBufferWindow”,
“typeVersion”: 1.3,
“position”: [
352,
224
],
“id”: “8d6c100e-7749-40f6-8c6a-5681b965c01c”,
“name”: “Simple Memory”
},
{
“parameters”: {
“respondWith”: “allIncomingItems”,
“options”: {}
},
“type”: “n8n-nodes-base.respondToWebhook”,
“typeVersion”: 1.5,
“position”: [
1200,
0
],
“id”: “720e1fa4-b6ae-4704-84f4-0fa736dd032f”,
“name”: “Respond to Webhook”
},
{
“parameters”: {
“descriptionType”: “manual”,
“toolDescription”: “Nutze dieses Tool, um einen bestehenden Patiententermin zu ändern.\n\nMögliche Änderungen:\n- Datum\n- Uhrzeit\n- Termindetails\n\nDieses Tool wird verwendet, wenn ein Patient:\n- seinen Termin verschieben möchte\n- eine Uhrzeit ändern möchte\n\nVor der Änderung muss die korrekte Event-ID ermittelt werden.\n”,
“operation”: “update”,
“calendar”: {
“__rl”: true,
“value”: “[email protected]”,
“mode”: “list”,
“cachedResultName”: “[email protected]”
},
“eventId”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Event_ID’, ``, ‘string’) }}”,
“updateFields”: {}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
480,
224
],
“id”: “cd684dfc-35f8-4621-a54c-562b77baab80”,
“name”: “Update an event”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “wAWIQSE5UdSN1lEu”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“descriptionType”: “manual”,
“toolDescription”: “Nutze dieses Tool, um eine Übersicht aller bestehenden Termine im Kalender zu erhalten.\n\nDieses Tool liefert:\n- Datum\n- Uhrzeit\n- Titel\n- Event-ID\n\nEs wird verwendet, um:\n- verfügbare oder belegte Termine zu prüfen\n- eine passende Event-ID zu finden\n\nDieses Tool liefert keine vollständigen Detailinformationen.\n”,
“operation”: “getAll”,
“calendar”: {
“__rl”: true,
“value”: “[email protected]”,
“mode”: “list”,
“cachedResultName”: “[email protected]”
},
“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”: [
608,
224
],
“id”: “05f80913-1c61-41e6-8a52-2976cf56c092”,
“name”: “Get many events”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “wAWIQSE5UdSN1lEu”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“descriptionType”: “manual”,
“toolDescription”: “Nutze dieses Tool, um einen bestehenden Patiententermin vollständig zu stornieren.\n\nDieses Tool wird verwendet, wenn ein Patient:\n- seinen Termin absagen möchte\n- keinen Ersatztermin wünscht\n\nVor der Stornierung muss:\n- die korrekte Event-ID eindeutig bestimmt werden\n”,
“operation”: “delete”,
“calendar”: {
“__rl”: true,
“value”: “[email protected]”,
“mode”: “list”,
“cachedResultName”: “[email protected]”
},
“eventId”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Event_ID’, ``, ‘string’) }}”,
“options”: {}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
736,
224
],
“id”: “e7a6c070-3f1d-497f-b599-8f1676cd07d1”,
“name”: “Delete an event”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “wAWIQSE5UdSN1lEu”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“descriptionType”: “manual”,
“toolDescription”: “Nutze dieses Tool, um einen neuen Patiententermin im Kalender zu erstellen.\n\nDieses Tool wird verwendet, wenn ein Patient:\n- einen neuen Termin buchen möchte\n- ein freies Zeitfenster bestätigt\n\nVor dem Erstellen muss der Agent:\n- Datum und Uhrzeit kennen\n- sicherstellen, dass der Termin noch frei ist\n\nJeder erstellte Kalendereintrag ist eine feste Terminreservierung.\n”,
“calendar”: {
“__rl”: true,
“value”: “[email protected]”,
“mode”: “list”,
“cachedResultName”: “[email protected]”
},
“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’) }}”,
“summary”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Summary’, ``, ‘string’) }}”
}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
864,
224
],
“id”: “1555b06f-b571-4feb-9058-7b7be24afe8d”,
“name”: “Create an event”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “wAWIQSE5UdSN1lEu”,
“name”: “Google Calendar account”
}
}
},
{
“parameters”: {
“descriptionType”: “manual”,
“toolDescription”: “Nutze dieses Tool, um die vollständigen Details eines einzelnen Termins abzurufen.\n\nDieses Tool wird verwendet, wenn:\n- ein bestimmter Termin eindeutig identifiziert werden soll\n- Detailinformationen benötigt werden\n\nDie Event-ID wird zuvor über Get many event ermittelt.\n”,
“operation”: “get”,
“calendar”: {
“__rl”: true,
“value”: “[email protected]”,
“mode”: “list”,
“cachedResultName”: “[email protected]”
},
“eventId”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘Event_ID’, ``, ‘string’) }}”,
“options”: {}
},
“type”: “n8n-nodes-base.googleCalendarTool”,
“typeVersion”: 1.3,
“position”: [
992,
224
],
“id”: “94064f49-fea1-49d2-a398-c144711151a2”,
“name”: “Get an event”,
“credentials”: {
“googleCalendarOAuth2Api”: {
“id”: “wAWIQSE5UdSN1lEu”,
“name”: “Google Calendar account”
}
}
}
],
“pinData”: {},
“connections”: {
“Webhook”: {
“main”: [
[
{
“node”: “AI Agent”,
“type”: “main”,
“index”: 0
}
]
]
},
“OpenAI Chat Model”: {
“ai_languageModel”: [
[
{
“node”: “AI Agent”,
“type”: “ai_languageModel”,
“index”: 0
}
]
]
},
“Simple Memory”: {
“ai_memory”: [
[
{
“node”: “AI Agent”,
“type”: “ai_memory”,
“index”: 0
}
]
]
},
“AI Agent”: {
“main”: [
[
{
“node”: “Respond to Webhook”,
“type”: “main”,
“index”: 0
}
]
]
},
“Update an event”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“Get many events”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“Delete an event”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“Create an event”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“Get an event”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
}
},
“active”: true,
“settings”: {
“executionOrder”: “v1”
},
“versionId”: “b7f1d641-f52e-4069-a453-fca58087bf3c”,
“meta”: {
“templateCredsSetupCompleted”: true,
“instanceId”: “b26871f112b0abeb14336426e43b61c88bd70829032f695584eeb2bff124b976”
},
“id”: “HdxOiDgkc6ckkVX4”,
“tags”:
}