This workflow follows the Google Calendar → HTTP Request 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 →
{
"name": "Rodopi Dent - Calendar Create Event",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "calendar-create",
"responseMode": "responseNode",
"options": {
"allowedOrigins": "*"
}
},
"id": "webhook",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
0
]
},
{
"parameters": {
"jsCode": "// Parse and validate input\nconst body = $input.first().json.body;\n\n// Support both patientName and title for blocking\nconst eventTitle = body.title || body.patientName;\n\n// Required fields\nif (!eventTitle) {\n throw new Error('\u0418\u043c\u0435 \u043d\u0430 \u043f\u0430\u0446\u0438\u0435\u043d\u0442 \u0438\u043b\u0438 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435 \u0435 \u0437\u0430\u0434\u044a\u043b\u0436\u0438\u0442\u0435\u043b\u043d\u043e');\n}\nif (!body.date) {\n throw new Error('\u0414\u0430\u0442\u0430 \u0435 \u0437\u0430\u0434\u044a\u043b\u0436\u0438\u0442\u0435\u043b\u043d\u0430');\n}\nif (!body.startTime) {\n throw new Error('\u041d\u0430\u0447\u0430\u043b\u0435\u043d \u0447\u0430\u0441 \u0435 \u0437\u0430\u0434\u044a\u043b\u0436\u0438\u0442\u0435\u043b\u0435\u043d');\n}\n\n// Calculate end time based on duration or endTime\nlet endTime;\nif (body.endTime) {\n endTime = body.endTime;\n} else {\n const duration = body.duration || 30; // Default 30 minutes\n const [hours, minutes] = body.startTime.split(':').map(Number);\n const startDate = new Date(`${body.date}T${body.startTime}:00`);\n const endDate = new Date(startDate.getTime() + duration * 60 * 1000);\n endTime = `${String(endDate.getHours()).padStart(2, '0')}:${String(endDate.getMinutes()).padStart(2, '0')}`;\n}\n\n// Appointment status handling\nconst statusVal = body.status || 'confirmed';\nconst statusLabels = { 'pending': '\u0427\u0430\u043a\u0430\u0449', 'confirmed': '\u041f\u043e\u0442\u0432\u044a\u0440\u0434\u0435\u043d', 'completed': '\u0417\u0430\u0432\u044a\u0440\u0448\u0435\u043d' };\nconst statusLabel = statusLabels[statusVal] || '\u041f\u043e\u0442\u0432\u044a\u0440\u0434\u0435\u043d';\n\n// Build summary - add \u23f3 prefix for pending\nlet summary = eventTitle;\nif (statusVal === 'pending') {\n summary = '\u23f3 ' + eventTitle;\n}\n\n// Build description with structured data\nlet description = '';\nif (body.patientPhone) {\n description += `\ud83d\udcde \u0422\u0435\u043b: ${body.patientPhone}\\n`;\n}\nif (body.procedure) {\n description += `\ud83e\uddb7 \u041f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430: ${body.procedure}\\n`;\n}\ndescription += `\ud83d\udccb \u0421\u0442\u0430\u0442\u0443\u0441: ${statusLabel}\\n`;\nif (body.notes) {\n description += `\ud83d\udcdd \u0411\u0435\u043b\u0435\u0436\u043a\u0438: ${body.notes}\\n`;\n}\n\n// Map color names to Google Calendar colorId (1-11)\nconst colorMap = {\n 'green': '10', // Basil (green)\n 'blue': '9', // Blueberry (blue)\n 'red': '11', // Tomato (red)\n 'yellow': '5', // Banana (yellow)\n 'purple': '3', // Grape (purple)\n 'orange': '6', // Tangerine (orange)\n 'pink': '4', // Flamingo (pink)\n 'gray': '8' // Graphite (gray)\n};\n// Status-based default colors: pending=yellow, completed=gray, confirmed=green\nconst statusColorDefaults = { 'pending': 'yellow', 'completed': 'gray', 'confirmed': 'green' };\nconst effectiveColor = body.colorId || statusColorDefaults[statusVal] || 'green';\nconst googleColorId = colorMap[effectiveColor] || colorMap['green'];\n\nreturn [{\n json: {\n summary: summary,\n description: description.trim(),\n startDateTime: `${body.date}T${body.startTime}:00`,\n endDateTime: `${body.date}T${endTime}:00`,\n date: body.date,\n duration: body.duration || 30,\n patientName: body.patientName || eventTitle,\n patientPhone: body.patientPhone || '',\n procedure: body.procedure || '',\n status: statusVal,\n colorId: googleColorId\n }\n}];"
},
"id": "prepare",
"name": "Prepare Event Data",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
220,
0
]
},
{
"parameters": {
"operation": "create",
"calendar": {
"__rl": true,
"mode": "id",
"value": "rodopi.dent@gmail.com"
},
"start": "={{ $json.startDateTime }}",
"end": "={{ $json.endDateTime }}",
"additionalFields": {
"summary": "={{ $json.summary }}",
"description": "={{ $json.description }}",
"sendUpdates": "all",
"colorId": "={{ $json.colorId || '' }}"
}
},
"id": "create-event",
"name": "Create Calendar Event",
"type": "n8n-nodes-base.googleCalendar",
"typeVersion": 1.2,
"position": [
440,
0
],
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Get created event details\nconst event = $input.first().json;\nconst prevData = $('Prepare Event Data').first().json;\n\nreturn [{\n json: {\n id: event.id,\n googleEventId: event.id,\n title: event.summary,\n patientName: prevData.patientName,\n patientPhone: prevData.patientPhone,\n procedure: prevData.procedure,\n date: prevData.date,\n duration: prevData.duration,\n status: prevData.status || 'confirmed',\n htmlLink: event.htmlLink,\n created: event.created,\n updated: event.updated\n }\n}];"
},
"id": "format-response",
"name": "Format Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
0
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: true, message: '\u0421\u044a\u0431\u0438\u0442\u0438\u0435\u0442\u043e \u0435 \u0441\u044a\u0437\u0434\u0430\u0434\u0435\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e', event: $json }) }}",
"options": {
"responseHeaders": {
"entries": [
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
}
},
"id": "respond-success",
"name": "Respond Success",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
880,
0
]
},
{
"parameters": {
"method": "POST",
"url": "https://n8n.simeontsvetanovn8nworkflows.site/webhook/patients-upsert",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"{{ $('Prepare Event Data').first().json.patientName }}\",\n \"phone\": \"{{ $('Prepare Event Data').first().json.patientPhone }}\"\n}",
"options": {}
},
"id": "save-patient",
"name": "Save Patient to Sheet",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
660,
150
],
"continueOnFail": true
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Prepare Event Data",
"type": "main",
"index": 0
}
]
]
},
"Prepare Event Data": {
"main": [
[
{
"node": "Create Calendar Event",
"type": "main",
"index": 0
}
]
]
},
"Create Calendar Event": {
"main": [
[
{
"node": "Format Response",
"type": "main",
"index": 0
},
{
"node": "Save Patient to Sheet",
"type": "main",
"index": 0
}
]
]
},
"Format Response": {
"main": [
[
{
"node": "Respond Success",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "Rodopi Dent"
}
]
}
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.
googleCalendarOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Rodopi Dent - Calendar Create Event. Uses googleCalendar, httpRequest. Webhook trigger; 6 nodes.
Source: https://github.com/Georgi-Piskov/RODOPI-DENT/blob/f071a84326ea5adf54e4eb20a2ba3e34aac5b728/n8n-workflows/12-calendar-create.json — 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.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c
Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.
📡 This workflow serves as the central Alpha Vantage API fetcher for Tesla trading indicators, delivering cleaned 20-point JSON outputs for three timeframes: , , and . It is required by the following a