Automatisation des rendez-vous WhatsApp via un assistant IA et des SMS intelligents (24/7)
Ceci est unSupport, AIworkflow d'automatisation du domainecontenant 25 nœuds.Utilise principalement des nœuds comme Code, Sms77, Switch, Webhook, HttpRequest, combinant la technologie d'intelligence artificielle pour une automatisation intelligente. Système de rendez-vous automatisé pour WhatsApp avec un assistant GPT-4, Cal.com et des rappels SMS
- •Point de terminaison HTTP Webhook (généré automatiquement par n8n)
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
- •Informations d'identification Google Sheets API
- •Clé API OpenAI
Nœuds utilisés (25)
Catégorie
{
"id": "IyhsZQh7TFAGsDqL",
"meta": {
"instanceId": "a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44",
"templateCredsSetupCompleted": true
},
"name": "Automate WhatsApp bookings with an AI assistant and smart SMS reminders (24/7)",
"tags": [],
"nodes": [
{
"id": "1d45c88a-5c71-42bb-9207-a7060a64030b",
"name": "Note adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
480
],
"parameters": {
"color": 4,
"width": 1620,
"height": 280,
"content": "# 🟩 STEP 3 — Send SMS Reminder Before Appointment\n\n"
},
"typeVersion": 1
},
{
"id": "1274c8bb-78fd-445f-b3bb-c1adedba3acc",
"name": "Note adhésive 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
-540
],
"parameters": {
"width": 1620,
"height": 460,
"content": "# 🟫 STEP 1 — Qualify User and Suggest Appointment"
},
"typeVersion": 1
},
{
"id": "bb147090-c21c-4b75-bfd7-92b1b61646f5",
"name": "Note adhésive 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
-60
],
"parameters": {
"color": 3,
"width": 1620,
"height": 520,
"content": "# 🟥 STEP 2 — Book Appointment Automatically\n\n"
},
"typeVersion": 1
},
{
"id": "3b2b3031-55a6-4c98-a6a5-75eb746b2c99",
"name": "Webhook Trigger (WhatsApp Input)",
"type": "n8n-nodes-base.webhook",
"position": [
-960,
-80
],
"webhookId": "6438cd95-74cb-4f40-a1a5-853706fe96f6",
"parameters": {
"path": "6438cd95-74cb-4f40-a1a5-853706fe96f6",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "6c7ffde6-b3bc-4162-b45d-8e483e347d49",
"name": "Commutateur : Flux Confirmation vs Chat",
"type": "n8n-nodes-base.switch",
"position": [
-740,
-80
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Discussion",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2b0aa9e5-7215-435b-8b66-fddb9973c7d0",
"operator": {
"type": "string",
"operation": "notContains"
},
"leftValue": "={{ $json.body.userInput }}",
"rightValue": "confirm"
}
]
},
"renameOutput": true
},
{
"outputKey": "Confirm booking",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ed81f2e7-f97d-4581-bc84-ed703db2ec08",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.body.userInput }}",
"rightValue": "confirm"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"name": "Assistant de réservation IA (Dr Firas)",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
40,
-460
],
"parameters": {
"text": "=input : {{ $json.body.userInput }}",
"options": {
"systemMessage": "=#IMPORTANT \nLes rendez-vous ne peuvent être pris qu’après avoir collecté le nom, l’e-mail/Courriel et le service choisi.\n\n#IDENTITÉ \nVous êtes l’assistant de Dr Firas, coach expert en automatisation n8n, sur WhatsApp.\n\n#CONTEXTE \n- Dr Firas propose des coachings et ateliers en ligne pour maîtriser n8n \n- Horaires : du lundi au vendredi, 9 h–18 h (heure de Paris) \n- Français et anglais possibles\n- La date d'aujourd'hui est : {{$now}}\n\n#SERVICES ET MAPPING (CRITIQUE) \n- « Audit express n8n » (30 min) – 40 $ – Event ID : 2638115 \n- « Coaching Workflow n8n » (60 min) – 65 $ – Event ID : 2638127 \n- « Atelier Automatisation Avancée » (90 min) – 99 $ – Event ID : 2638131 \n\nQuand l’utilisateur choisit un service, mémorisez l’Event ID correspondant.\n\n#TON \nDynamique, professionnel et chaleureux. Emojis légers 👍🤖.\n\n#FLUX DE CONVERSATION\n\n## 1. Accueil \n« Bonjour ! Je suis l’assistant de Dr Firas, prêt à vous guider pour votre session n8n. Puis-je vous poser quelques questions ? »\n\n## 2. Choix du service (une question à la fois) \na) « Quel service souhaitez-vous ? » \n- Si « je ne sais pas » ou « que proposez-vous » → listez les 3 services avec durée, prix et bénéfice court. \n- Sinon, continuez.\n\n## 3. Collecte des infos client \n« Parfait ! Pour réserver votre [nom du service], j’ai besoin de votre prénom et de votre e-mail. »\n\n→ Après avoir reçu nom + e-mail/Courriel , enregistrez dans le Google Sheet Prospect (nom, e-mail, téléphone={{ $json.body.phoneNumber }}, service, Event ID, résumé).\n\n## 4. Proposition de créneaux \n« Souhaitez-vous voir les disponibilités immédiatement ? » \n- Si oui : \n 1. Appelez l’outil **Get Availability** avec : \n - Event ID du service \n - startTime = maintenant (ISO 8601, UTC, ex. `2025-06-13T12:00:00Z`) \n - endTime = +48 h (ISO 8601, UTC) \n - max 5 créneaux \n 2. Convertissez chaque horaire UTC en heure de Paris (+02:00) et affichez-les en plain text (ex. “14:30”).\n\n## 5. Choix du créneau \n« Lequel de ces créneaux vous convient ? » \n- L’utilisateur répond date+heure → \n - Demandez « Tapez “oui” pour confirmer ce créneau ». \n - À « oui », enregistrez via Google Sheet Update_Leads (nom, e-mail, service, Event ID, date+heure). \n - Puis : « Votre rendez-vous est fixé au [date] à [heure] (heure de Paris). Tapez “confirm” pour finaliser. »\n\n## 6. Confirmation finale \n- À “confirm” → \n - Confirmez la réservation et rappelez la politique d’annulation 24 h à l’avance. \n - Proposez un lien d’ajout au calendrier si besoin.\n\n#CONTRAINTES OUTIL “Get Availability” \n- Toujours ISO 8601 UTC \n- startTime = maintenant, endTime = +48 h \n- Maximum 5 créneaux \n- Plain text, < 400 car.\n\n#RÈGLES GÉNÉRALES \n- Une question à la fois \n- Ne jamais redemander une info déjà fournie \n- “RESET” relance la conversation depuis le début \n"
},
"promptType": "define"
},
"typeVersion": 1.8
},
{
"id": "03d391f5-43b5-462e-8c56-cdce426f9751",
"name": "LLM : Modèle de chat GPT-4o",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-200,
-260
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o",
"cachedResultName": "gpt-4o"
},
"options": {}
},
"credentials": {
"openAiApi": {
"id": "6h3DfVhNPw9I25nO",
"name": "OpenAi account"
}
},
"typeVersion": 1.2
},
{
"id": "365fc08f-6514-4182-b77f-86a13ef55576",
"name": "Mémoire de conversation IA",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-40,
-260
],
"parameters": {
"sessionKey": "={{ $json.body.contactId }}",
"sessionIdType": "customKey",
"contextWindowLength": 50
},
"typeVersion": 1.3
},
{
"id": "96eeb9b5-aea9-46cc-893f-4ea3697a3fb5",
"name": "Créer un nouveau prospect dans Google Sheet",
"type": "n8n-nodes-base.googleSheetsTool",
"position": [
140,
-260
],
"parameters": {
"columns": {
"value": {
"Nom": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Nom', ``, 'string') }}",
"Courriel": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Courriel', ``, 'string') }}",
"Résumé": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('R_sum_', `ici il y a le résumé de toute la conversation`, 'string') }}",
"ID du contact": "={{ $json.body.contactId }}",
"Numéro de téléphone": "={{ $json.body.phoneNumber }}"
},
"schema": [
{
"id": "Nom",
"type": "string",
"display": true,
"required": false,
"displayName": "Nom",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Courriel",
"type": "string",
"display": true,
"required": false,
"displayName": "Courriel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Numéro de téléphone",
"type": "string",
"display": true,
"required": false,
"displayName": "Numéro de téléphone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Résumé",
"type": "string",
"display": true,
"required": false,
"displayName": "Résumé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Réservé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Réservé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Nom de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ID de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date du rendez-vous",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date du rendez-vous",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Rappel SMS envoyé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Rappel SMS envoyé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID du contact",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID du contact",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"ID du contact"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit#gid=0",
"cachedResultName": "mes RDV"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit?usp=drivesdk",
"cachedResultName": "MES RDV"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
},
{
"id": "9fcb6a32-34e7-4c5a-997a-cd0fe58f62cd",
"name": "Mettre à jour le prospect avec les détails de réservation",
"type": "n8n-nodes-base.googleSheetsTool",
"position": [
320,
-260
],
"parameters": {
"columns": {
"value": {
"ID du contact": "={{ $json.body.contactId }}",
"Date du rendez-vous": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Date_du_rendez-vous', ``, 'string') }}",
"ID de l’événement": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('ID_de_l__v_nement', ``, 'string') }}",
"Nom de l’événement": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Nom_de_l__v_nement', ``, 'string') }}"
},
"schema": [
{
"id": "Nom",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Courriel",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Courriel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Numéro de téléphone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Numéro de téléphone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Résumé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Résumé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Réservé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Réservé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Nom de l’événement",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Nom de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID de l’événement",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date du rendez-vous",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Date du rendez-vous",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Rappel SMS envoyé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Rappel SMS envoyé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID du contact",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID du contact",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"ID du contact"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit#gid=0",
"cachedResultName": "mes RDV"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit?usp=drivesdk",
"cachedResultName": "MES RDV"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
},
{
"id": "9e1a6470-0937-4190-9d24-259ea2749190",
"name": "Récupérer les créneaux horaires disponibles",
"type": "@n8n/n8n-nodes-langchain.toolHttpRequest",
"position": [
520,
-260
],
"parameters": {
"url": "https://api.cal.com/v2/slots/available",
"sendQuery": true,
"sendHeaders": true,
"parametersQuery": {
"values": [
{
"name": "eventTypeId"
},
{
"name": "startTime"
},
{
"name": "endTime"
}
]
},
"toolDescription": "Appelez cet outil pour récupérer la disponibilité des rendez-vous.\nVous devez impérativement utiliser le fuseau horaire de Paris.\nRespectez strictement le format ISO pour les dates, par exemple :\n2025-01-01T09:00:00-02:00\nExemple de schéma d’entrée :\n{\n \"startTime\": \"...\",\n \"endTime\": \"...\"\n}",
"parametersHeaders": {
"values": [
{
"name": "Authorization",
"value": "Bearer cal_live_6cd60e462f8dc9b065fb48624e5918d8",
"valueProvider": "fieldValue"
},
{
"name": "Content-Type",
"value": "application/json",
"valueProvider": "fieldValue"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "5d8dc1ce-020f-4df3-88cc-7f61594a3347",
"name": "Envoyer la réponse à WhatsApp",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
-460
],
"parameters": {
"options": {},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.1
},
{
"id": "5cd00123-c0ea-48f9-85e6-e496a0bd6620",
"name": "Récupérer les détails du prospect",
"type": "n8n-nodes-base.googleSheets",
"position": [
-420,
140
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('Webhook Trigger (WhatsApp Input)').item.json.body.contactId }}",
"lookupColumn": "ID du contact"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit#gid=0",
"cachedResultName": "mes RDV"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit?usp=drivesdk",
"cachedResultName": "MES RDV"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
},
{
"id": "9696140f-857f-42b6-9bb9-3d25f5d893d4",
"name": "Normaliser l'heure de réservation (format UTC)",
"type": "n8n-nodes-base.code",
"position": [
-200,
140
],
"parameters": {
"jsCode": "const input = $input.first().json['Date du rendez-vous']; // e.g.,\n\"2025-06-04T09:00:00+02:00\"\nfunction normalizeToUTCZFormat(dateString) {\ntry {\nif\n(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$/.test(dateString)\n) {\nreturn new Date(dateString).toISOString();\n}\nconst date = new Date(dateString);\nif (isNaN(date.getTime())) {\nthrow new Error(\"Invalid date format\");\n}\nreturn date.toISOString(); // Returns in UTC with Z\n} catch (e) {\nreturn `Invalid input: ${e.message}`;\n}\n}\nreturn [\n{\njson: {\noriginal: input,\nnormalized: normalizeToUTCZFormat(input),\n},\n},\n];"
},
"typeVersion": 2
},
{
"id": "6d2ef19a-93d1-46f1-bc31-ad1010d3bb4a",
"name": "Envoyer la réservation",
"type": "n8n-nodes-base.httpRequest",
"position": [
20,
140
],
"parameters": {
"url": "https://api.cal.com/v2/bookings",
"method": "POST",
"options": {},
"jsonBody": "={\n\"eventTypeId\": {{ $('Retrieve Prospect Details').item.json['ID de l’événement'] }},\n\"start\": \"{{ $json.normalized }}\",\n\"attendee\": {\n\"name\": \"{{ $('Retrieve Prospect Details').item.json.Nom }}\",\n\"email\": \"{{ $('Retrieve Prospect Details').item.json.Courriel }}\",\n\"timeZone\": \"Europe/Paris\"\n},\n\"bookingFieldsResponses\": {\n\"title\": \"{{ $('Retrieve Prospect Details').item.json['Résumé'] }}\"\n}\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer cal_live_6cd60e462f8dc9b065fb48624e5918d8"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "cal-api-version",
"value": "2024-08-13"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "472dc55f-b42f-483f-b6cc-1f8c25f0158e",
"name": "Formater la date pour la lisibilité (affichage)",
"type": "n8n-nodes-base.code",
"position": [
240,
140
],
"parameters": {
"jsCode": "const input = $('Retrieve Prospect Details').first().json['Date du rendez-vous']; \nfunction formatToReadableDate(dateString) {\ntry {\nconst date = new Date(dateString);\nif (isNaN(date.getTime())) throw new Error(\"Invalid date\");\nconst options = {\ntimeZone: \"Europe/Berlin\", // Ensures correct local time\nmonth: \"long\",\nday: \"numeric\",\nhour: \"numeric\",\nminute: \"2-digit\",\nhour12: true,\n};\nconst formatted = date.toLocaleString(\"en-US\", options);\n// Example output: \"June 4, 09:00 AM\" → make it shorter like\n\"June 4, 9am\"\nreturn formatted\n.replace(\":00\", \"\") // remove :00 if exact hour\n.replace(\"AM\", \"am\")\n.replace(\"PM\", \"pm\");\n} catch (e) {\nreturn `Invalid input: ${e.message}`;\n}\n}\nreturn [\n{\njson: {\noriginal: input,\nformatted: formatToReadableDate(input),\n},\n},\n]; "
},
"typeVersion": 2
},
{
"id": "7f0f86bc-8199-4d81-8bce-e96ced534f6e",
"name": "Vérifier le statut de réservation (succès ou erreur)",
"type": "n8n-nodes-base.switch",
"position": [
460,
140
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "succeeded",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cbf9b691-0bc1-4a14-b35d-96664d82bc91",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Send Booking').item.json.status }}",
"rightValue": "success"
}
]
},
"renameOutput": true
},
{
"outputKey": "Failed",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f78214f9-ecd4-4913-aef0-9a2a453b052c",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Send Booking').item.json.status }}",
"rightValue": "error"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "108c9a6b-a345-4f33-ab22-113b6e63914b",
"name": "Webhook Response : Réservation confirmée",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
-20
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "\n[\n{\n\"output\": \"Votre réservation a été effectuée avec succès. Vous recevrez bientôt un e-mail de confirmation pour votre massage, RDV : .\"\n}\n]"
},
"typeVersion": 1.1
},
{
"id": "8c3d9734-7aad-4445-9810-29d7045fbc78",
"name": "Webhook Response : Échec de réservation",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
700,
280
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "[\n{\n\"output\": \"Il semble que le créneau horaire que vous avez choisi ne soit plus disponible. Veuillez en sélectionner un autre.\"\n}\n]"
},
"typeVersion": 1.1
},
{
"id": "2a3ed659-5cec-497b-bde8-f6a15585cc41",
"name": "Marquer la réservation comme confirmée dans Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
920,
140
],
"parameters": {
"columns": {
"value": {
"Réservé": "confirm",
"ID du contact": "={{ $('Retrieve Prospect Details').item.json['ID du contact'] }}"
},
"schema": [
{
"id": "Nom",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Courriel",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Courriel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Numéro de téléphone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Numéro de téléphone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Résumé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Résumé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Réservé",
"type": "string",
"display": true,
"required": false,
"displayName": "Réservé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Nom de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ID de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date du rendez-vous",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date du rendez-vous",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Rappel SMS envoyé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Rappel SMS envoyé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID du contact",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID du contact",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"ID du contact"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit#gid=0",
"cachedResultName": "mes RDV"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit?usp=drivesdk",
"cachedResultName": "MES RDV"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
},
{
"id": "5bfa51a3-e939-41e8-a1df-b4e59c4feef1",
"name": "Trigger : Vérifier les rendez-vous toutes les heures",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-420,
580
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "0413b7b7-b523-4e22-ad4a-40d7342abed9",
"name": "Lire les rendez-vous à venir depuis Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-200,
580
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit#gid=0",
"cachedResultName": "mes RDV"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PsuURJg5nxVnb18OMDShjC-sTA9i_32pyBSjfswOpqc/edit?usp=drivesdk",
"cachedResultName": "MES RDV"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
},
{
"id": "408e1330-29e4-4de7-b681-1bb372b5f841",
"name": "Filtrer les rendez-vous dans les 2 prochaines heures",
"type": "n8n-nodes-base.code",
"position": [
20,
580
],
"parameters": {
"jsCode": "const nowParis = new Date(\n new Date().toLocaleString(\"en-US\", { timeZone: \"Europe/Paris\" })\n);\nconst nowTimestamp = nowParis.getTime();\nconst twoHoursFromNow = nowTimestamp + 2 * 60 * 60 * 1000;\n\nreturn items\n .filter(item => {\n const booked = item.json[\"Réservé\"]?.toLowerCase() === \"confirm\";\n const reminderSent = item.json[\"Rappel SMS envoyé\"]?.toLowerCase() === \"envoyer\";\n const rawDate = item.json[\"Date du rendez-vous\"];\n if (!booked || reminderSent || !rawDate) {\n return false;\n }\n\n const appointmentTimestamp = Date.parse(rawDate);\n return appointmentTimestamp > nowTimestamp &&\n appointmentTimestamp <= twoHoursFromNow;\n })\n .map(item => {\n const rawDate = item.json[\"Date du rendez-vous\"];\n const date = new Date(rawDate);\n if (isNaN(date.getTime())) {\n item.json.appointmentDisplayTime = \"(Invalid date)\";\n return item;\n }\n\n const options = {\n timeZone: \"Europe/Paris\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true\n };\n\n const formatted = date.toLocaleString(\"en-US\", options)\n .replace(\":00\", \"\")\n .replace(\"AM\", \"AM\")\n .replace(\"PM\", \"PM\");\n\n item.json.appointmentDisplayTime = formatted;\n return item;\n });\n"
},
"typeVersion": 2
},
{
"id": "0a9d6747-85d2-400e-a9fd-b5768ae4605c",
"name": "Envoyer un rappel SMS",
"type": "n8n-nodes-base.sms77",
"position": [
240,
580
],
"parameters": {
"to": "={{ $('Read Upcoming Appointments from Sheet').item.json['Numéro de téléphone'] }}",
"message": "=Bonjour {{ $json.Nom }}, ceci est un petit rappel : votre rendez-vous pour {{ $json['Nom de l’événement'] }} est prévu dans les 2 prochaines heures ",
"options": {}
},
"credentials": {
"sms77Api": {
"id": "nC2L4tQyF03xEMAX",
"name": "seven account"
}
},
"typeVersion": 1
},
{
"id": "3a01ec5e-57ea-43ac-8e59-97d66e85454f",
"name": "Marquer le SMS comme envoyé dans Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
460,
580
],
"parameters": {
"columns": {
"value": {
"ID du contact": "={{ $('Read Upcoming Appointments from Sheet').item.json['ID du contact'] }}",
"Rappel SMS envoyé": "envoyer"
},
"schema": [
{
"id": "Nom",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Courriel",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Courriel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Numéro de téléphone",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Numéro de téléphone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Résumé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Résumé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Réservé",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Réservé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Nom de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Nom de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID de l’événement",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ID de l’événement",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date du rendez-vous",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date du rendez-vous",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Rappel SMS envoyé",
"type": "string",
"display": true,
"required": false,
"displayName": "Rappel SMS envoyé",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ID du contact",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID du contact",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"ID du contact"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "="
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "="
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "51us92xkOlrvArhV",
"name": "Google Sheets account"
}
},
"typeVersion": 4.5
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "5c82e86c-e3b2-4b70-b686-a782edbaee55",
"connections": {
"6d2ef19a-93d1-46f1-bc31-ad1010d3bb4a": {
"main": [
[
{
"node": "472dc55f-b42f-483f-b6cc-1f8c25f0158e",
"type": "main",
"index": 0
}
]
]
},
"0a9d6747-85d2-400e-a9fd-b5768ae4605c": {
"main": [
[
{
"node": "3a01ec5e-57ea-43ac-8e59-97d66e85454f",
"type": "main",
"index": 0
}
]
]
},
"365fc08f-6514-4182-b77f-86a13ef55576": {
"ai_memory": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "ai_memory",
"index": 0
}
]
]
},
"03d391f5-43b5-462e-8c56-cdce426f9751": {
"ai_languageModel": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"5cd00123-c0ea-48f9-85e6-e496a0bd6620": {
"main": [
[
{
"node": "9696140f-857f-42b6-9bb9-3d25f5d893d4",
"type": "main",
"index": 0
}
]
]
},
"9e1a6470-0937-4190-9d24-259ea2749190": {
"ai_tool": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "ai_tool",
"index": 0
}
]
]
},
"6c7ffde6-b3bc-4162-b45d-8e483e347d49": {
"main": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "main",
"index": 0
}
],
[
{
"node": "5cd00123-c0ea-48f9-85e6-e496a0bd6620",
"type": "main",
"index": 0
}
]
]
},
"f7f43574-cfed-4448-983f-dc53343ec4ab": {
"main": [
[
{
"node": "5d8dc1ce-020f-4df3-88cc-7f61594a3347",
"type": "main",
"index": 0
}
]
]
},
"3b2b3031-55a6-4c98-a6a5-75eb746b2c99": {
"main": [
[
{
"node": "6c7ffde6-b3bc-4162-b45d-8e483e347d49",
"type": "main",
"index": 0
}
]
]
},
"96eeb9b5-aea9-46cc-893f-4ea3697a3fb5": {
"ai_tool": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "ai_tool",
"index": 0
}
]
]
},
"9696140f-857f-42b6-9bb9-3d25f5d893d4": {
"main": [
[
{
"node": "6d2ef19a-93d1-46f1-bc31-ad1010d3bb4a",
"type": "main",
"index": 0
}
]
]
},
"108c9a6b-a345-4f33-ab22-113b6e63914b": {
"main": [
[
{
"node": "2a3ed659-5cec-497b-bde8-f6a15585cc41",
"type": "main",
"index": 0
}
]
]
},
"9fcb6a32-34e7-4c5a-997a-cd0fe58f62cd": {
"ai_tool": [
[
{
"node": "f7f43574-cfed-4448-983f-dc53343ec4ab",
"type": "ai_tool",
"index": 0
}
]
]
},
"472dc55f-b42f-483f-b6cc-1f8c25f0158e": {
"main": [
[
{
"node": "7f0f86bc-8199-4d81-8bce-e96ced534f6e",
"type": "main",
"index": 0
}
]
]
},
"0413b7b7-b523-4e22-ad4a-40d7342abed9": {
"main": [
[
{
"node": "408e1330-29e4-4de7-b681-1bb372b5f841",
"type": "main",
"index": 0
}
]
]
},
"5bfa51a3-e939-41e8-a1df-b4e59c4feef1": {
"main": [
[
{
"node": "0413b7b7-b523-4e22-ad4a-40d7342abed9",
"type": "main",
"index": 0
}
]
]
},
"7f0f86bc-8199-4d81-8bce-e96ced534f6e": {
"main": [
[
{
"node": "108c9a6b-a345-4f33-ab22-113b6e63914b",
"type": "main",
"index": 0
}
],
[
{
"node": "8c3d9734-7aad-4445-9810-29d7045fbc78",
"type": "main",
"index": 0
}
]
]
},
"408e1330-29e4-4de7-b681-1bb372b5f841": {
"main": [
[
{
"node": "0a9d6747-85d2-400e-a9fd-b5768ae4605c",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Support, Intelligence Artificielle
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Dr. Firas
@drfirasAutomation expert and certified trainer. I create hands-on courses to master automation with n8n. Contact me to access my exclusive training and start building powerful workflows today. 🚀
Partager ce workflow