Automatización de citas de WhatsApp con un asistente de IA y recordatorios de SMS inteligentes (24/7)

Avanzado

Este es unSupport, AIflujo de automatización del dominio deautomatización que contiene 25 nodos.Utiliza principalmente nodos como Code, Sms77, Switch, Webhook, HttpRequest, combinando tecnología de inteligencia artificial para lograr automatización inteligente. Automatización del sistema de citas de WhatsApp con asistente GPT-4, Cal.com y recordatorios por SMS

Requisitos previos
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Pueden requerirse credenciales de autenticación para la API de destino
  • Credenciales de API de Google Sheets
  • Clave de API de OpenAI
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "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": "Nota adhesiva",
      "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": "Nota adhesiva1",
      "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": "Nota adhesiva3",
      "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": "Switch: Flujo de confirmación 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": "Asistente de reservas con 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: GPT-4o Chat Model",
      "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": "Memoria de conversación con 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": "Crear nuevo prospecto en 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": "Actualizar prospecto con detalles de reserva",
      "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": "Obtener franjas horarias 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": "Enviar respuesta a WhatsApp",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        700,
        -460
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "5cd00123-c0ea-48f9-85e6-e496a0bd6620",
      "name": "Recuperar detalles del prospecto",
      "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": "Normalizar hora de reserva (formato 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": "Enviar reserva",
      "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": "Formatear fecha para legibilidad (visualización)",
      "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": "Verificar estado de reserva (éxito o error)",
      "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: Reserva confirmada",
      "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: Reserva fallida",
      "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": "Marcar reserva como confirmada en 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: Verificar citas cada hora",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -420,
        580
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0413b7b7-b523-4e22-ad4a-40d7342abed9",
      "name": "Leer citas próximas desde 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": "Filtrar citas dentro de las próximas 2 horas",
      "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": "Enviar recordatorio 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": "Marcar SMS como enviado en 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
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Soporte, Inteligencia Artificial

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos25
Categoría2
Tipos de nodos14
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor
Dr. Firas

Dr. Firas

@drfiras

Automation 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. 🚀

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34