{
  "name": "MediFlow \u2014 Prise de Rendez-vous WhatsApp (Evolution API)",
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "nodes": [
    {
      "id": "3cca0317-e1d3-4a91-a119-88e5c259097b",
      "name": "\ud83d\udce5 Webhook Evolution API",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -4576,
        2368
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "mediflow-rdv",
        "responseMode": "responseNode",
        "options": {}
      }
    },
    {
      "id": "f5332879-f396-493f-9089-2fab2098528c",
      "name": "\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -4352,
        2368
      ],
      "parameters": {
        "jsCode": "// Parse le payload Evolution API et extrait le num\u00e9ro + message\nconst body = $input.first().json.body;\nlet phone = '';\nlet message = '';\nlet messageType = 'text';\n\ntry {\n  if (body.data) {\n    phone = body.data.key?.remoteJid?.replace('@s.whatsapp.net', '') || '';\n    message = body.data.message?.conversation ||\n              body.data.message?.extendedTextMessage?.text || '';\n    messageType = body.data.messageType || 'conversation';\n    const isFromMe = body.data?.key?.fromMe || false;\n    if (isFromMe) return [{ json: { skip: true, reason: 'message_sortant' } }];\n  } else if (body.messages) {\n    phone = body.messages[0]?.key?.remoteJid?.replace('@s.whatsapp.net', '') || '';\n    message = body.messages[0]?.message?.conversation || '';\n    if (body.messages[0]?.key?.fromMe) return [{ json: { skip: true, reason: 'message_sortant' } }];\n  }\n} catch(e) {\n  console.log('Parse error:', e.message);\n}\n\n// Ignorer les messages non-texte (audio, images)\nif (!message || messageType === 'audioMessage' || messageType === 'imageMessage') {\n  return [{ json: { skip: true, reason: 'pas_texte', phone } }];\n}\n\nreturn [{ json: { phone, message, messageType, timestamp: new Date().toISOString() } }];"
      }
    },
    {
      "id": "f174cd85-9803-40c0-814f-b1040486cfbe",
      "name": "\ud83d\udea6 Message valide ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -4128,
        2368
      ],
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.skip }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              }
            }
          ]
        }
      }
    },
    {
      "id": "26eb3dfc-726a-4e1b-a1f2-7e3d273ea682",
      "name": "\ud83d\udc64 Chercher Patient (Google Sheets)",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        -3728,
        2176
      ],
      "alwaysOutputData": true,
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "PATIENTS",
          "mode": "name"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "telephone",
              "lookupValue": "={{ $('\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone').item.json.phone }}"
            }
          ]
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "6358dbec-c150-4149-bb0a-1e140f292976",
      "name": "\ud83c\udd95 Patient connu ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -3520,
        2176
      ],
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $('\ud83d\udc64 Chercher Patient (Google Sheets)').item.json.patient_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ]
        }
      }
    },
    {
      "id": "d4126e7b-9824-4ae4-a107-f17de62095b2",
      "name": "\u2795 Cr\u00e9er Nouveau Patient",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        -3376,
        2592
      ],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "PATIENTS",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "telephone": "={{ $('\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone').item.json.phone }}",
            "patient_id": "=PAT_{{ $now.toFormat('yyyyMMddHHmmss') }}",
            "date_inscription": "={{ $now.toISO() }}"
          }
        }
      }
    },
    {
      "id": "6b13162a-897f-4fe1-b7b9-734f8e4b7413",
      "name": "\ud83d\udc4b Envoyer Message Bienvenue",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -3168,
        2624
      ],
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_EVOLUTION_API_URL/message/sendText/YOUR_INSTANCE_NAME",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "number",
              "value": "={{ $('\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone').item.json.phone }}"
            },
            {
              "name": "text",
              "value": "Bonjour et bienvenue chez MediFlow ! \ud83d\udc4b\n\nJe suis MediBot, votre assistant pour la prise de rendez-vous m\u00e9dicaux.\n\nComment puis-je vous aider aujourd'hui ? Vous pouvez me dire par exemple :\n- \"Je veux prendre un rendez-vous\"\n- \"Je veux annuler mon rendez-vous\"\n- \"J'ai une urgence m\u00e9dicale\""
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "5449abe4-aa9a-48ce-91ed-ef2e811f5401",
      "name": "\ud83d\udccb Lire \u00c9tat Conversation",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -3296,
        2176
      ],
      "parameters": {
        "jsCode": "// R\u00e9cup\u00e8re l'\u00e9tat de conversation persist\u00e9 en Google Sheets\nconst patientData = $('\ud83d\udc64 Chercher Patient (Google Sheets)').item.json;\nconst messageData = $('\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone').item.json;\n\nconst etatConv = patientData.etat_conversation || 'LIBRE';\nconst creneauxProposes = patientData.creneaux_proposes || '';\n\nreturn [{\n  json: {\n    phone: messageData.phone,\n    message: messageData.message,\n    patient_id: patientData.patient_id || '',\n    patient_prenom: patientData.prenom || '',\n    etat_conversation: etatConv,\n    creneaux_proposes: creneauxProposes\n  }\n}];"
      }
    },
    {
      "id": "cf75af23-5df4-4204-b086-ec6c1d4acc28",
      "name": "\u23f3 En attente de choix ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -3072,
        2176
      ],
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.etat_conversation }}",
              "rightValue": "ATTENTE_CRENEAU",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ]
        }
      }
    },
    {
      "id": "64c5a635-42d6-45d6-a51b-5cbd49937397",
      "name": "Pr\u00e9pare Requ\u00eate Claude",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2944,
        2912
      ],
      "parameters": {
        "jsCode": "// Construit le prompt Claude selon l'\u00e9tat de conversation\nconst etat = $('\ud83d\udccb Lire \u00c9tat Conversation').item.json.etat_conversation || 'LIBRE';\nconst message = $('\ud83d\udccb Lire \u00c9tat Conversation').item.json.message || '';\n\nconst body = {\n  model: \"claude-haiku-4-5-20251001\",\n  max_tokens: 600,\n  system: `Tu es MediBot, l'assistant de prise de rendez-vous d'une clinique priv\u00e9e.\n\nServices : cardiologie, p\u00e9diatrie, g\u00e9n\u00e9raliste, gyn\u00e9cologie, dermatologie.\n\u00c9tat conversation : ${etat}\n\nR\u00c8GLES :\n1. RDV sans sp\u00e9cialit\u00e9 \u2192 retourne PRENDRE_RDV, specialite=null, liste les sp\u00e9cialit\u00e9s dans message_reponse\n2. \u00c9tat ATTENTE_SPECIALITE \u2192 le message est la sp\u00e9cialit\u00e9 choisie\n3. Sp\u00e9cialit\u00e9 pr\u00e9cis\u00e9e \u2192 retourne PRENDRE_RDV avec specialite renseign\u00e9e\n4. Urgence \u2192 retourne URGENCE\n5. Autre \u2192 retourne AUTRE avec r\u00e9ponse utile\n\nRetourne UNIQUEMENT un JSON valide :\n{\n  \"intention\": \"PRENDRE_RDV\" | \"ANNULER_RDV\" | \"CONFIRMER_RDV\" | \"URGENCE\" | \"AUTRE\",\n  \"specialite\": null | \"cardiologie\" | \"p\u00e9diatrie\" | \"g\u00e9n\u00e9raliste\" | \"gyn\u00e9cologie\" | \"dermatologie\",\n  \"message_reponse\": \"message chaleureux en fran\u00e7ais\",\n  \"demander_specialite\": false\n}`,\n  messages: [{ role: \"user\", content: \"Message du patient : \" + message }]\n};\n\nreturn [{ json: { claudeBody: JSON.stringify(body) } }];"
      }
    },
    {
      "id": "177206be-e2e0-4625-997c-7481e8472dd2",
      "name": "\ud83e\udd16 Claude \u2014 Analyser Intention",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -2704,
        2912
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "anthropicApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.parse($json.claudeBody) }}",
        "options": {
          "timeout": 30000
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "68b7a017-3d1e-46b1-9b5b-e9e90f99d208",
      "name": "\u2699\ufe0f Parser R\u00e9ponse Claude",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2496,
        2912
      ],
      "parameters": {
        "jsCode": "// Parse la r\u00e9ponse JSON de Claude et attache les donn\u00e9es patient\nconst response = $input.first().json;\nlet claudeData = {};\n\ntry {\n  const rawText = response.content[0].text;\n  const cleaned = rawText.replace(/```json|```/g, '').trim();\n  claudeData = JSON.parse(cleaned);\n} catch(e) {\n  claudeData = {\n    intention: 'AUTRE',\n    message_reponse: 'Bonjour ! Je suis MediBot, votre assistant. Comment puis-je vous aider ?',\n    demander_specialite: false\n  };\n}\n\nclaudeData.phone = $('\ud83d\udccb Lire \u00c9tat Conversation').item.json.phone;\nclaudeData.patient_id = $('\ud83d\udccb Lire \u00c9tat Conversation').item.json.patient_id;\nclaudeData.patient_prenom = $('\ud83d\udccb Lire \u00c9tat Conversation').item.json.patient_prenom;\n\nreturn [{ json: claudeData }];"
      }
    },
    {
      "id": "89870dba-36e7-42d1-bfc7-ab861990eae7",
      "name": "\ud83d\udd00 Router par Intention",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        -2304,
        2848
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.intention }}",
                    "rightValue": "URGENCE",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ]
              }
            },
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.intention }}",
                    "rightValue": "PRENDRE_RDV",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  },
                  {
                    "leftValue": "={{ $json.specialite }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty",
                      "singleValue": true
                    }
                  }
                ]
              }
            },
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.intention }}",
                    "rightValue": "ANNULER_RDV",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      }
    },
    {
      "id": "0b7fc34d-a5b3-4769-b30c-a9d98b16dd79",
      "name": "\ud83d\udcc5 Cr\u00e9er RDV Confirm\u00e9",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        -2016,
        1024
      ],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "RENDEZ-VOUS",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "rdv_id": "=RDV_{{ $now.toFormat('yyyyMMddHHmmss') }}",
            "patient_id": "={{ $json.patient_id }}",
            "patient_telephone": "={{ $json.phone }}",
            "medecin_nom": "={{ $json.creneau_choisi.medecin_nom }}",
            "specialite": "={{ $json.creneau_choisi.specialite }}",
            "date_rdv": "={{ $json.creneau_choisi.date }}",
            "heure_rdv": "={{ $json.creneau_choisi.heure_debut }}",
            "lieu": "={{ $json.creneau_choisi.lieu || 'Clinique MediFlow' }}",
            "statut": "CONFIRME",
            "date_creation": "={{ $now.toISO() }}"
          }
        }
      }
    },
    {
      "id": "51a92ed2-12b3-4bbb-883f-be37ead1c0e2",
      "name": "\u2705 R\u00e9ponse Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        752,
        2480
      ],
      "parameters": {
        "respondWith": "json",
        "responseBody": "{ \"status\": \"ok\" }",
        "options": {
          "responseCode": 200
        }
      }
    }
  ],
  "connections": {
    "\ud83d\udce5 Webhook Evolution API": {
      "main": [
        [
          {
            "node": "\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd0d Extraire Message & T\u00e9l\u00e9phone": {
      "main": [
        [
          {
            "node": "\ud83d\udea6 Message valide ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udea6 Message valide ?": {
      "main": [
        [
          {
            "node": "\ud83d\udc64 Chercher Patient (Google Sheets)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\u2705 R\u00e9ponse Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udc64 Chercher Patient (Google Sheets)": {
      "main": [
        [
          {
            "node": "\ud83c\udd95 Patient connu ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83c\udd95 Patient connu ?": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Lire \u00c9tat Conversation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\u2795 Cr\u00e9er Nouveau Patient",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2795 Cr\u00e9er Nouveau Patient": {
      "main": [
        [
          {
            "node": "\ud83d\udc4b Envoyer Message Bienvenue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udc4b Envoyer Message Bienvenue": {
      "main": [
        [
          {
            "node": "\u2705 R\u00e9ponse Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb Lire \u00c9tat Conversation": {
      "main": [
        [
          {
            "node": "\u23f3 En attente de choix ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u23f3 En attente de choix ?": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 Claude \u2014 Analyser Intention",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Pr\u00e9pare Requ\u00eate Claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pr\u00e9pare Requ\u00eate Claude": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 Claude \u2014 Analyser Intention",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 Claude \u2014 Analyser Intention": {
      "main": [
        [
          {
            "node": "\u2699\ufe0f Parser R\u00e9ponse Claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2699\ufe0f Parser R\u00e9ponse Claude": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Router par Intention",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcc5 Cr\u00e9er RDV Confirm\u00e9": {
      "main": [
        [
          {
            "node": "\u2705 R\u00e9ponse Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "tags": [
    "mediflow",
    "whatsapp",
    "healthcare",
    "claude-ai"
  ]
}