AutomationFlowsGeneral › Reagendamiento

Reagendamiento

Reagendamiento. Uses executeWorkflowTrigger, redis, n8n-nodes-evolution-api, dataTable. Event-driven trigger; 73 nodes.

Event trigger★★★★★ complexity73 nodesExecute Workflow TriggerRedisN8N Nodes Evolution ApiData TableGoogle Calendar
General Trigger: Event Nodes: 73 Complexity: ★★★★★ Added:
Reagendamiento — n8n workflow card showing Execute Workflow Trigger, Redis, N8N Nodes Evolution Api integration

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 →

Download .json
{
  "name": "Reagendamiento",
  "nodes": [
    {
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "CallerID"
            },
            {
              "name": "Message"
            },
            {
              "name": "Instance"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        -112,
        656
      ],
      "id": "beabcd89-f0fa-4f01-9a0c-c94796eeff23",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "state",
        "key": "={{ $json.CallerID }}-state",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        336,
        288
      ],
      "id": "7220a0bd-798b-4441-81dc-a3d9e804157e",
      "name": "Redis",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "empty",
                      "singleValue": true
                    },
                    "id": "499e6b74-e44a-478f-9477-599ef97cc445"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Inicio"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "732a7223-5dba-4eec-a8e4-0a2e6f67de6b",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Nombre",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Nombre"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "5aaca3f3-7a1f-479e-8396-7f639a6805d0",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Eleccion",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Eleccion"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "c0def2a0-eb7f-42ef-83b3-1f00a34c233b",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Reagendar",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Reagendar"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "ed95d16b-41e1-4ada-afc3-8068a9c0bc6c",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Fecha",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Fecha"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "cac52561-204c-4dcf-b6ae-c69ca96bc9dd",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Hora",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Hora"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "69256363-aec0-43e3-bf64-4e8be27fc803",
                    "leftValue": "={{ $json.state }}",
                    "rightValue": "Confirmacion",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Confirmacion"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        560,
        224
      ],
      "id": "4c5ebf71-9ec2-4d70-be07-a4c3e907d318",
      "name": "Switch"
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-state",
        "value": "Nombre"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1008,
        -288
      ],
      "id": "9433c83f-0e81-46ea-a2fa-8a37ebeaad09",
      "name": "Set_name",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\ud83d\udd04 Elegiste *reagendar una cita*.\n\nPor favor, escrib\u00ed el *nombre de la persona* que figura en la consulta para poder continuar.\n\nSi dese\u00e1s volver al men\u00fa principal, escrib\u00ed *CANCELAR*.\n",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        784,
        -288
      ],
      "id": "e368622c-b506-4d40-ab90-b4445de6d05d",
      "name": "Inicio",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u274c No se encontr\u00f3 ninguna cita asociada a ese nombre.\n\nPor favor, verific\u00e1 el nombre ingresado e intent\u00e1 nuevamente.\nSi necesit\u00e1s ayuda, escrib\u00ed *CANCELAR* para volver al inicio.\n",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1232,
        96
      ],
      "id": "3185912a-79ec-474a-89cd-c88eb456996d",
      "name": "No_Date_With_That_Name",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u26a0\ufe0f Encontramos una cita asociada a ese nombre, pero el n\u00famero desde el que est\u00e1s escribiendo no coincide con el registrado en la reserva.\n\nPor favor, escrib\u00ed el *n\u00famero de tel\u00e9fono* desde el cual se realiz\u00f3 la reserva para poder continuar.\n",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1456,
        80
      ],
      "id": "5ad5f780-9f67-4d46-97ae-98b545322ff3",
      "name": "Number_not_Associated",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-state",
        "value": "Numero"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1680,
        80
      ],
      "id": "f3e6380a-2056-4a55-a5c7-96d1612387c4",
      "name": "Set_number",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "wA0dcDuSPu44zLSy",
          "mode": "list",
          "cachedResultName": "Appointment",
          "cachedResultUrl": "/projects/2FKcChTlWLe9b3wY/datatables/wA0dcDuSPu44zLSy"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "paciente_nombre",
              "condition": "ilike",
              "keyValue": "={{ $('When Executed by Another Workflow').item.json.Message.toTitleCase() }}"
            },
            {
              "keyName": "estado",
              "condition": "neq",
              "keyValue": "cancelado"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        784,
        -96
      ],
      "id": "f0f3e3df-8468-47ae-826e-73b28c245eed",
      "name": "GetTurnos",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $json.Instance }}",
        "remoteJid": "={{ $json.CallerID }}",
        "messageText": "={{ $json.mensaje }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1904,
        -208
      ],
      "id": "308c6b2f-201a-45c4-ac4f-e9c1f11d6514",
      "name": "Unica_Cita",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('Message_Builder').item.json.CallerID }}-state",
        "value": "Reagendar"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2128,
        -208
      ],
      "id": "aec9e32b-a351-4c26-bda6-64d4e08d3b49",
      "name": "Set_cancelacion",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "6cf103df-c30f-4639-ab1c-a6fdfa1a40ad",
              "leftValue": "={{ $json }}",
              "rightValue": 0,
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1008,
        -96
      ],
      "id": "005ba53d-edca-49a6-81f0-05d51582833a",
      "name": "Is_name_associated"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 3
          },
          "conditions": [
            {
              "id": "eea10787-6084-4c2c-9d6d-dd22fd64d147",
              "leftValue": "={{ $json.paciente_telefono }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              }
            },
            {
              "id": "4edf745f-f222-41eb-b37e-a710f5e71b0f",
              "leftValue": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
              "rightValue": "={{ $json.paciente_telefono}}",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              }
            }
          ],
          "combinator": "or"
        },
        "looseTypeValidation": true,
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1232,
        -96
      ],
      "id": "2889cb43-8d2a-4011-80fe-9dc6ece9cb3d",
      "name": "Is_number_associated"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "d4b53fe6-2696-4ead-a55d-89f9c36b0bfe",
              "leftValue": "={{ $json.unica_cita }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1680,
        -112
      ],
      "id": "04758230-eedd-4f02-9aff-8565764a0d97",
      "name": "Is_date_unique"
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('Message_Builder').item.json.CallerID }}-dateID",
        "value": "={{ $('Message_Builder').item.json.cita.id.toString() }}",
        "keyType": "string"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2352,
        -208
      ],
      "id": "961bab46-5a1d-41ef-a528-18b02a953fa8",
      "name": "Set_DateID",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('When Executed by Another Workflow').item.json.Message.toUpperCase() }}",
                    "rightValue": "SI",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "d1cb1abb-bae5-4ffb-8c41-e8f3eebe172f"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "confirmado"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "db831cfd-f3e0-406c-9ece-dd7856bc1cd1",
                    "leftValue": "={{ $('When Executed by Another Workflow').item.json.Message.toUpperCase() }}",
                    "rightValue": "NO",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "cancelado"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        784,
        576
      ],
      "id": "5591d8b6-fc39-4829-8329-f2a4e8b625f0",
      "name": "Switch1"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u274c Respuesta inv\u00e1lida. Por favor respond\u00e9 SI o NO.",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1008,
        880
      ],
      "id": "6463ca27-c570-4982-91b8-45f432d2c650",
      "name": "Neither",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "9npekj3aPag37ifbW5rTQ",
          "mode": "list",
          "cachedResultUrl": "/workflow/9npekj3aPag37ifbW5rTQ",
          "cachedResultName": "Deletion_of_Redis"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "CallerID": "={{ $('When Executed by Another Workflow').item.json.CallerID }}"
          },
          "matchingColumns": [
            "CallerID"
          ],
          "schema": [
            {
              "id": "CallerID",
              "displayName": "CallerID",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        1232,
        768
      ],
      "id": "5b199ed1-2193-4b8b-b365-68272c98f24d",
      "name": "Call 'Deletion_of_Redis'"
    },
    {
      "parameters": {
        "content": "{CallerID}-state\n{CallerID}-DoctorId\n{CallerID}-fecha\n{CallerID}-fechaHoraInicio\n{CallerID}-fechaHoraFin\n{CallerID}-doctores_disponibles\n{CallerID}-HorariosDisponibles\n{{CallerID }}-menu\n{{ CallerID }}-name",
        "height": 272
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -512
      ],
      "id": "d75a0cce-9925-41cb-9aea-b4297d10c647",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u2139\ufe0f El reagendamiento fue cancelado.",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1008,
        688
      ],
      "id": "6a0c5f9e-0ca8-4abf-8d5e-15d1bbc33334",
      "name": "Cancelar",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Citas existentes\nconst appointments = $('GetTurnos').all().map(i => i.json);\n\n// Fecha actual\nconst ahora = new Date();\n\n// Filtrar citas futuras y reservadas\nconst citasFuturas = appointments.filter(cita => {\n  return (\n    cita.estado === 'reservado' &&\n    new Date(cita.fecha_hora_inicio) > ahora\n  );\n});\n\n// Si no tiene citas futuras\nif (citasFuturas.length === 0) {\n  return [{\n    json: {\n      tiene_citas: false,\n      mensaje: '\u274c No ten\u00e9s citas futuras registradas para reagendar.'\n    }\n  }];\n}\n\n// Si tiene una sola cita\nif (citasFuturas.length === 1) {\n  const cita = citasFuturas[0];\n  const inicio = new Date(cita.fecha_hora_inicio);\n\n  const mensaje =\n`\ud83d\udcc5 Ten\u00e9s una cita programada:\n\n\ud83d\udcc6 Fecha: ${inicio.toLocaleDateString('es-ES')}\n\u23f0 Hora: ${inicio.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' })}\n\n\u00bfDese\u00e1s *reagendar* esta cita?\nRespond\u00e9 *SI* para continuar o *NO* para mantenerla.`;\n\n  return [{\n    json: {\n      unica_cita: true,\n      cita,\n      mensaje,\n      CallerID: $('When Executed by Another Workflow').first().json.CallerID,\n      Instance: $('When Executed by Another Workflow').first().json.Instance\n    }\n  }];\n}\n\n// Si tiene m\u00e1s de una cita\nlet menu = `\ud83d\udcc5 Ten\u00e9s las siguientes citas programadas:\\n\\n`;\n\ncitasFuturas.forEach((cita, index) => {\n  const inicio = new Date(cita.fecha_hora_inicio);\n  menu += `${index + 1}\ufe0f\u20e3 ${inicio.toLocaleDateString('es-ES')} - ${inicio.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' })}\\n`;\n});\n\nmenu += `\\nPor favor, respond\u00e9 con el *n\u00famero* de la cita que dese\u00e1s *reagendar*.`;\n\nreturn [{\n  json: {\n    unica_cita: false,\n    citas: citasFuturas,\n    mensaje: menu,\n    CallerID: $('When Executed by Another Workflow').first().json.CallerID,\n    Instance: $('When Executed by Another Workflow').first().json.Instance\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1456,
        -112
      ],
      "id": "72fbc5dc-398e-401a-997e-0ad3ab8f87cb",
      "name": "Message_Builder"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $json.Instance }}",
        "remoteJid": "={{ $json.CallerID }}",
        "messageText": "={{ $json.mensaje }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1904,
        -16
      ],
      "id": "1075e057-916e-4a53-9dbf-635dba7d1a5d",
      "name": "Multiples_Citas",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('Message_Builder').item.json.CallerID }}-HorariosDisponibles",
        "value": "={{ $('Message_Builder').item.json.citas.toJsonString() }}"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2352,
        -16
      ],
      "id": "2e21f3e7-66ee-4dfe-866d-ae1bac4a52b4",
      "name": "Set_HorariosDisponibles",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('Message_Builder').item.json.CallerID }}-state",
        "value": "Eleccion"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2128,
        -16
      ],
      "id": "38f9cefd-4b58-4d8e-8e69-816da9f633b0",
      "name": "Set_eleccion",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "citas",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-HorariosDisponibles",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        784,
        288
      ],
      "id": "9db6fa18-ea2d-4e56-8f94-4a2d11a288cd",
      "name": "Get_HorariosDisponibles",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// JSON en formato string (array de citas)\nconst jsonString = $input.first().json.citas;\n\n// Opci\u00f3n ingresada por el usuario\nconst opcionRaw = $('When Executed by Another Workflow').first().json.Message;\nconst opcion = parseInt(opcionRaw, 10);\n\n// Parsear JSON string a JSON real\nconst citas = JSON.parse(jsonString);\n\n// Validar que sea n\u00famero\nif (isNaN(opcion)) {\n  return [{\n    json: {\n      valido: false,\n      mensaje: '\u274c Opci\u00f3n inv\u00e1lida. Por favor, respond\u00e9 con un n\u00famero.'\n    }\n  }];\n}\n\n// Validar rango\nif (opcion < 1 || opcion > citas.length) {\n  return [{\n    json: {\n      valido: false,\n      mensaje: '\u274c El n\u00famero ingresado no corresponde a ninguna cita.'\n    }\n  }];\n}\n\n// Obtener la cita seleccionada (1 \u2192 \u00edndice 0)\nconst citaSeleccionada = citas[opcion - 1];\n\n// Fecha de inicio de la cita\nconst inicio = new Date(citaSeleccionada.fecha_hora_inicio);\n\n// Mensaje de reagendamiento\nconst mensaje =\n`\ud83d\udcc6 Fecha actual: ${inicio.toLocaleDateString('es-ES')}\n\u23f0 Hora actual: ${inicio.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' })}\n\n\u00bfPara qu\u00e9 d\u00eda quer\u00e9s agendar la consulta?\n\n\ud83d\udcc5 Escrib\u00ed la fecha en formato DD/MM/AAAA.`;\n\n// OK\nreturn [{\n  json: {\n    valido: true,\n    eleccion_usuario: opcion,\n    cita_seleccionada: citaSeleccionada,\n    mensaje\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1008,
        288
      ],
      "id": "f606e637-97b7-4a34-83b5-bd31e0d23c68",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "4c55dea2-9a0c-4719-97cf-03f33cc4712c",
              "leftValue": "={{ $json.Message.toUpperCase() }}",
              "rightValue": "CANCELAR",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        112,
        656
      ],
      "id": "9b9acaf4-87e7-4999-bfc5-901bf93c1ea4",
      "name": "Canceled?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "ddc0e4cb-e3b1-4c3c-99d8-3a773a2db127",
              "leftValue": "={{ $json.valido }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1232,
        288
      ],
      "id": "35c2559d-0729-42ed-a2e8-5f5d326cd191",
      "name": "If"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "={{ $json.mensaje }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1456,
        288
      ],
      "id": "2384aec8-7e9e-448a-ab2c-430669b921db",
      "name": "Eleccion_valida",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-dateID",
        "value": "={{ $('Code in JavaScript').item.json.cita_seleccionada.id.toString() }}",
        "keyType": "string"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1904,
        288
      ],
      "id": "83071630-7976-4fbe-832d-e5bb4abb701e",
      "name": "Set_DateID1",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\ud83d\uddd1\ufe0f Tu turno fue cancelado correctamente.",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1232,
        2096
      ],
      "id": "45ba7be6-0327-4f01-b1a6-9fab9c452345",
      "name": "cancelacion",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "398f759c-6c2e-4e17-8723-237c215b9358",
              "leftValue": "={{ $('When Executed by Another Workflow').item.json.Message.toUpperCase() }}",
              "rightValue": "NO",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1008,
        2096
      ],
      "id": "285d0a46-4674-474c-b7ca-ee43d3c12374",
      "name": "If2"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u2705 \u00a1Turno confirmado!\n\nTu consulta qued\u00f3 *reagendada* para:\n\n\ud83d\udcc5 {{ $('Get_date_inicio').item.json.dateInicio.toDateTime().toFormat('dd/MM/yyyy')  }}\n\ud83d\udd52 {{ $('Get_date_inicio').item.json.dateInicio.toDateTime().toLocaleString({timeStyle: 'short'}) }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        2544,
        1840
      ],
      "id": "d0ceefd7-c467-46f4-87ba-71fd6af0c504",
      "name": "Confirmacion",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "dateFin",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fechaHoraFin",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1456,
        1840
      ],
      "id": "baf636ae-85e1-4aa4-9d7a-933fc6f8d578",
      "name": "Get_date_fin",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "dateInicio",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fechaHoraInicio",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1232,
        1840
      ],
      "id": "4830d965-7ec0-40a6-b9c5-fa4e4d626779",
      "name": "Get_date_inicio",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "e2f2a6a2-e6a8-40b0-a429-d1ce21795dfa",
              "leftValue": "={{ $('When Executed by Another Workflow').item.json.Message.toUpperCase() }}",
              "rightValue": "SI",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        784,
        1936
      ],
      "id": "772427cf-3035-4422-99c3-d51dc884009f",
      "name": "If1"
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "HorariosDisponibles",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-HorariosDisponibles",
        "keyType": "list",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1008,
        1440
      ],
      "id": "c5a456df-41ac-4d83-b5f6-5908af808c94",
      "name": "get_HorariosDisponibles",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Input del usuario (ej: \"1\", \"2\", etc.)\nconst choiceRaw = $('When Executed by Another Workflow').first().json.Message;\nconst index = parseInt(choiceRaw, 10);\n\n// Validar input num\u00e9rico\nif (isNaN(index) || index < 1) {\n  return [{\n    json: {\n      valido: false,\n      mensaje: '\u274c Opci\u00f3n inv\u00e1lida. Respond\u00e9 con el n\u00famero del horario.'\n    }\n  }];\n}\n\n// Horarios disponibles (array de \"HH:mm\")\nconst horariosDisponibles = $('get_HorariosDisponibles').first().json.HorariosDisponibles;\n\n// Validar que est\u00e9 dentro del array\nif (index > horariosDisponibles.length) {\n  return [{\n    json: {\n      valido: false,\n      mensaje: '\u274c El horario seleccionado no existe.'\n    }\n  }];\n}\n\n// Hora elegida (HH:mm)\nconst horaElegida = horariosDisponibles[index - 1];\n\n// Fecha base ISO\nconst fechaBaseISO = $('Get_date').first().json.fecha_selected;\nconst inicioElegido = new Date(fechaBaseISO);\n\n// Setear hora elegida\nconst [hh, mm] = horaElegida.split(':').map(Number);\ninicioElegido.setUTCHours(hh, mm, 0, 0);\n\n// Duraci\u00f3n\nconst duracion = $('GetDoctor1').first().json.duracion_consulta;\nconst finElegido = new Date(inicioElegido);\nfinElegido.setMinutes(finElegido.getMinutes() + duracion);\n\n// Mensaje de confirmaci\u00f3n\nconst mensaje =\n`\ud83d\udcc5 *Confirmaci\u00f3n de turno*\n\n\ud83d\udc68\u200d\u2695\ufe0f Doctor: ${$('GetDoctor1').first().json.nombre}\n\ud83d\udc64 Paciente: ${$('Get_appointment1').first().json.paciente_nombre}\n\ud83d\udcc6 Fecha: ${inicioElegido.toLocaleDateString('es-ES')}\n\u23f0 Hora: ${horaElegida}\n\u231b Duraci\u00f3n: ${duracion} minutos\n\n\u00bfLos datos son correctos?\nRespond\u00e9 *SI* para confirmar o *NO* para cancelar.`;\n\n// OK\nreturn [{\n  json: {\n    valido: true,\n    fecha_hora_inicio: inicioElegido.toISOString(),\n    fecha_hora_fin: finElegido.toISOString(),\n    mensaje\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2128,
        1456
      ],
      "id": "c725e9f4-8ada-47c7-a208-2d32f7f85dca",
      "name": "Code in JavaScript3"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "={{ $json.mensaje }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        2352,
        1456
      ],
      "id": "d1a23df0-07c0-4c3b-bb0e-9128acb21925",
      "name": "Hora1",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "hMRPl1eK7rwrIssD",
          "mode": "list",
          "cachedResultName": "Doctor",
          "cachedResultUrl": "/projects/2FKcChTlWLe9b3wY/datatables/hMRPl1eK7rwrIssD"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyValue": "={{ $json.doctor_id }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1904,
        1456
      ],
      "id": "0395f93d-7ac8-4b96-b64e-3004490d1416",
      "name": "GetDoctor1",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fechaHoraInicio",
        "value": "={{ $('Code in JavaScript3').item.json.fecha_hora_inicio }}"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2576,
        1456
      ],
      "id": "a0fd6361-47a3-4006-87fd-6f67fe7f0147",
      "name": "Set_date_inicio",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fechaHoraFin",
        "value": "={{ $('Code in JavaScript3').item.json.fecha_hora_fin }}"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        2800,
        1456
      ],
      "id": "4b310c9c-bc3a-451c-8db8-581551a1f0a4",
      "name": "Set_date_fin",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-state",
        "value": "Confirmacion",
        "keyType": "string"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        3024,
        1456
      ],
      "id": "e1f740f6-ff79-4a30-9fca-d0042928468c",
      "name": "Set_confirmacion",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "propertyName": "fecha_selected",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fecha",
        "options": {}
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1232,
        1456
      ],
      "id": "3aeab449-9c23-4bee-b1bb-e687d541dccd",
      "name": "Get_date",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=No pude reconocer la fecha que enviaste.\nPor favor, escribila en el formato dd/MM/yyyy (por ejemplo: 15/03/2026).",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1232,
        1264
      ],
      "id": "296f1c44-3d74-41d2-84cd-80ae957f5a35",
      "name": "FechaInvalida",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const texto = $('When Executed by Another Workflow').first().json.Message;\n\n// 1. Validar formato dd/MM/yyyy con regex estricta\nconst regex = /^(0[1-9]|[12][0-9]|3[01])\\/(0[1-9]|1[0-2])\\/\\d{4}$/;\n\nif (!regex.test(texto)) {\n  return [{ json: { valido: false, motivo: 'Formato inv\u00e1lido (dd/MM/yyyy)' } }];\n}\n\n// 2. Validar que la fecha exista realmente\nconst [dia, mes, anio] = texto.split('/').map(Number);\nconst fecha = new Date(anio, mes - 1, dia);\n\nconst fechaValida =\n  fecha.getFullYear() === anio &&\n  fecha.getMonth() === mes - 1 &&\n  fecha.getDate() === dia;\n\nif (!fechaValida) {\n  return [{ json: { valido: false, motivo: 'La fecha no existe' } }];\n}\n\n// 3. Fecha v\u00e1lida\nreturn [{\n  json: {\n    valido: true,\n    fecha_original: texto,\n    fecha_date: fecha.toISOString()\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        784,
        1072
      ],
      "id": "f34128da-183f-43ee-b807-5f352d7a6b79",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 3
          },
          "conditions": [
            {
              "id": "60e72980-9c72-416d-ab7f-402b7d4a2a2a",
              "leftValue": "={{ $json.valido }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "or"
        },
        "looseTypeValidation": true,
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1008,
        1072
      ],
      "id": "6f3ee9e9-2c9b-4bb9-a5d1-3321f0ebf04e",
      "name": "Is_Date"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=Lo siento, {{ $json.nombre.includes('Dr.')? 'el ' : \"la \"}}{{ $json.nombre}} no atiende el d\u00eda seleccionado. ",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        2800,
        1136
      ],
      "id": "ab885be2-154c-4771-9d6a-fa169ab8afe6",
      "name": "NoAtiende",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=La fecha que indicaste corresponde a un d\u00eda que ya pas\u00f3.\nPor favor, env\u00edame una fecha posterior a hoy en el formato dd/MM/yyyy (por ejemplo: 25/03/2026).",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1456,
        1232
      ],
      "id": "93073a76-7b0e-4058-8e94-832ce99ce738",
      "name": "FechaPasada",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "1e924288-3c7c-4f79-9bca-2883bde79c02",
              "leftValue": "={{ $json.fecha_date }}",
              "rightValue": "={{ $now }}",
              "operator": {
                "type": "dateTime",
                "operation": "after"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1232,
        1072
      ],
      "id": "cdbf7267-f270-48b7-9082-59988f4a45d0",
      "name": "Is_Valid_Date"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "Vh1ixrYCpUuuKazI",
          "mode": "list",
          "cachedResultName": "Horario",
          "cachedResultUrl": "/projects/2FKcChTlWLe9b3wY/datatables/Vh1ixrYCpUuuKazI"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "doctor_id",
              "keyValue": "={{ $json.doctor_id }}"
            },
            {
              "keyName": "dia_semana",
              "keyValue": "={{ $('Code in JavaScript1').item.json.fecha_date.toDateTime().extract(\"weekday\") }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        1904,
        1040
      ],
      "id": "f3c17093-0cfd-4182-b207-54fe9f0c0601",
      "name": "GetHorario",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "6fbcb57f-c881-468d-a6b5-e1720df81894",
              "leftValue": "={{ $('GetHorario').item.json.dia_semana }}",
              "rightValue": "",
              "operator": {
                "type": "number",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        2576,
        1040
      ],
      "id": "7eb1ba24-1eda-4abd-a168-37530c0abcc5",
      "name": "Is_attending that date"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "={{ $json.mensaje }}",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        3024,
        944
      ],
      "id": "f00ea52d-c903-42e8-b9a0-c095ff191226",
      "name": "Hora",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "hMRPl1eK7rwrIssD",
          "mode": "list",
          "cachedResultName": "Doctor",
          "cachedResultUrl": "/projects/2FKcChTlWLe9b3wY/datatables/hMRPl1eK7rwrIssD"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyValue": "={{ $('Get_appointment').item.json.doctor_id }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        2352,
        1040
      ],
      "id": "b0447a35-2ed0-4395-89bf-889fb04cd7be",
      "name": "GetDoctor",
      "alwaysOutputData": true,
      "executeOnce": true
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-fecha",
        "value": "={{ $('Code in JavaScript1').item.json.fecha_date }}"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        3696,
        944
      ],
      "id": "fb605b0d-65bb-4600-95e8-2a9c6cf611d6",
      "name": "Set_date",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-state",
        "value": "Hora",
        "keyType": "string"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        3920,
        944
      ],
      "id": "81dc7eeb-0484-439c-aeb2-7144896b98f8",
      "name": "Set_hora",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "push",
        "list": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-HorariosDisponibles",
        "messageData": "={{ $('Code in JavaScript4').item.json.horariosDisponibles }}",
        "tail": true
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        3472,
        944
      ],
      "id": "5915c7f3-307a-4492-93fe-94c0a1c995f3",
      "name": "Save_Horarios",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "9npekj3aPag37ifbW5rTQ",
          "mode": "list",
          "cachedResultUrl": "/workflow/9npekj3aPag37ifbW5rTQ",
          "cachedResultName": "Deletion_of_Redis"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "CallerID": "={{ $('When Executed by Another Workflow').item.json.CallerID }}"
          },
          "matchingColumns": [
            "CallerID"
          ],
          "schema": [
            {
              "id": "CallerID",
              "displayName": "CallerID",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        2768,
        1936
      ],
      "id": "daa2ed7f-9248-46aa-88a3-894f13fce9e4",
      "name": "Call 'DeleteKeys'"
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=Lo siento, no entend\u00ed tu respuesta.\n\nPor favor, respond\u00e9 con:\nSI \ud83d\udc49 para confirmar el turno  \nNO \ud83d\udc49 para cancelarlo",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1232,
        2288
      ],
      "id": "66e8f20e-9669-4f24-bbbd-8f4e7332674e",
      "name": "cancelacion1",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const appointments = $('GetTurnos1').all().map(i => i.json);\nconst horarios = $('GetHorario').all().map(i => i.json);\n\nconst doctorNombre = $('GetDoctor').first().json.nombre;\nconst duracion_consulta = $('GetDoctor').first().json.duracion_consulta; // minutos\nconst fechaISO = $('Code in JavaScript1').first().json.fecha_date;\n\nconst fecha = new Date(fechaISO);\nconst diaSemana = fecha.getUTCDay(); // 0=domingo ... 6=s\u00e1bado\nlet prefix;\nconst horariosDelDia = horarios.filter(h => h.dia_semana === diaSemana);\nif(doctorNombre.startsWith(\"Dr.\")){\n  prefix = 'el';\n} else {\n  prefix = 'la';\n}\nconst citasReservadas = appointments\n  .filter(a => a.estado === 'reservado')\n  .map(a => ({\n    inicio: new Date(a.fecha_hora_inicio),\n    fin: new Date(a.fecha_hora_fin),\n  }));\n\nconst disponibles = [];\n\nfor (const h of horariosDelDia) {\n  let hora = h.hora_inicio;\n\n  while (hora < h.hora_fin) {\n    const horas = Math.floor(hora / 100);\n    const minutos = hora % 100;\n\n    const inicioSlot = new Date(fecha);\n    inicioSlot.setUTCHours(horas, minutos, 0, 0);\n\n    const finSlot = new Date(inicioSlot);\n    finSlot.setMinutes(finSlot.getMinutes() + duracion_consulta);\n\n    const ocupado = citasReservadas.some(c =>\n      inicioSlot < c.fin && finSlot > c.inicio\n    );\n\n    if (!ocupado && finSlot.getUTCHours() * 100 + finSlot.getUTCMinutes() <= h.hora_fin) {\n      disponibles.push(inicioSlot.toISOString().substring(11, 16));\n    }\n\n    // \u23ed avanzar seg\u00fan duraci\u00f3n real\n    const totalMin = minutos + duracion_consulta;\n    hora = horas * 100 + totalMin;\n\n    // corregir overflow de minutos (> 60)\n    if (hora % 100 >= 60) {\n      hora += Math.floor((hora % 100) / 60) * 40;\n    }\n  }\n}\n\nconst emojis = ['1\ufe0f\u20e3','2\ufe0f\u20e3','3\ufe0f\u20e3','4\ufe0f\u20e3','5\ufe0f\u20e3','6\ufe0f\u20e3','7\ufe0f\u20e3','8\ufe0f\u20e3','9\ufe0f\u20e3','\ud83d\udd1f'];\nconst fechaTexto = fecha.toLocaleDateString('es-ES');\nlet mensaje;\n\nif (disponibles.length === 0) {\n  mensaje = `\u274c No hay horarios disponibles para ${prefix} ${doctorNombre} el ${fechaTexto}.\\n\\n` +\n            `Por favor, eleg\u00ed otra fecha o contact\u00e1 con recepci\u00f3n.`;\n} else {\n  const emojis = ['1\ufe0f\u20e3','2\ufe0f\u20e3','3\ufe0f\u20e3','4\ufe0f\u20e3','5\ufe0f\u20e3','6\ufe0f\u20e3','7\ufe0f\u20e3','8\ufe0f\u20e3','9\ufe0f\u20e3','\ud83d\udd1f'];\n\n  mensaje = `Estos son los horarios disponibles para ${prefix} ${doctorNombre} el ${fechaTexto}:\\n\\n`;\n\n  disponibles.forEach((h, i) => {\n    mensaje += `${emojis[i] || '\u23f1\ufe0f'} ${h}\\n`;\n  });\n\n  mensaje += `\\nRespond\u00e9 escribiendo el numero de la hora exacta que prefieras. \\n(Ejemplo: 2)`;\n}\n\nreturn [\n  {\n    json: {\n      mensaje,\n      horariosDisponibles: disponibles,\n      hayDisponibilidad: disponibles.length > 0,\n      duracion_consulta\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2800,
        944
      ],
      "id": "5b85397a-6a75-4c6e-8ac9-52a33fe6ff45",
      "name": "Code in JavaScript4"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "value": "wA0dcDuSPu44zLSy",
          "mode": "list",
          "cachedResultName": "Appointment",
          "cachedResultUrl": "/projects/2FKcChTlWLe9b3wY/datatables/wA0dcDuSPu44zLSy"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "doctor_id",
              "keyValue": "={{ $('Get_appointment').item.json.doctor_id }}"
            },
            {
              "keyName": "fecha_hora_inicio",
              "condition": "gte",
              "keyValue": "={{ $('Is_Valid_Date').item.json.fecha_date.toDateTime() }}"
            },
            {
              "keyName": "fecha_hora_fin",
              "condition": "lt",
              "keyValue": "={{ $('Is_Valid_Date').item.json.fecha_date.toDateTime().plus(1,\"days\") }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1.1,
      "position": [
        2128,
        1040
      ],
      "id": "c689ec2f-104f-45de-860b-440f82d7c7ce",
      "name": "GetTurnos1",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "ebe600fb-d3ac-4886-9b64-109ecbede96a",
              "leftValue": "={{ $('Code in JavaScript4').item.json.hayDisponibilidad }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        3248,
        944
      ],
      "id": "214bd5ae-0e83-43b4-a2de-b56f9147d632",
      "name": "If4"
    },
    {
      "parameters": {
        "operation": "set",
        "key": "={{ $('When Executed by Another Workflow').item.json.CallerID }}-state",
        "value": "Fecha",
        "keyType": "string"
      },
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1680,
        496
      ],
      "id": "67a0cba9-3deb-4006-aaab-95b84356361e",
      "name": "Set_fecha",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "messages-api",
        "instanceName": "={{ $('When Executed by Another Workflow').item.json.Instance }}",
        "remoteJid": "={{ $('When Executed by Another Workflow').item.json.CallerID }}",
        "messageText": "=\u00bfPara qu\u00e9 d\u00eda quer\u00e9s agendar la consulta?\n\n\ud83d\udcc5 Escrib\u00ed la fecha en formato DD/MM/AAAA.",
        "options_message": {}
      },
      "type": "n8n-nodes-evolution-api.evolutionApi",
      "typeVersion": 1,
      "position": [
        1456,
        496
      ],
      "id": "73fdb586-c866-446a-a8fb-8b33681d6180",
      "name": "Fecha",
      "credentials": {
        "evolutionApi": {
          "name": "<your credential>"
 

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Reagendamiento. Uses executeWorkflowTrigger, redis, n8n-nodes-evolution-api, dataTable. Event-driven trigger; 73 nodes.

Source: https://github.com/ignacioelizeche/BackOffice-Odonto/blob/13b047f47b8a3442a521b3ff148aff5b26d8f464/N8N/Reagendamiento.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.

N8N Nodes Evolution Api, Redis, Data Table +2
General

Prevent concurrent workflow runs using Redis. Uses executeWorkflowTrigger, manualTrigger, stickyNote, executeWorkflow. Event-driven trigger; 43 nodes.

Execute Workflow Trigger, Redis, Stop And Error
General

This workflow sets a small "lock" value in Redis so that only one copy of a long job can run at the same time. If another trigger fires while the job is still busy, the workflow sees the lock, stops e

Execute Workflow Trigger, Redis, Stop And Error
General

This implementation aggregates incoming data into a Redis list from potentially concurrent workflow executions. It buffers the data for a set period before a single execution retrieves and processes t

Crypto, Redis, Execute Workflow Trigger
General

This workflow provides a reusable error handling, audit logging, and observability pattern for n8n workflows using two n8n custom Data Tables: and .

Error Trigger, Data Table, Execute Workflow Trigger