The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Vitalis - Respuestas WhatsApp Twilio",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "twilio-respuestas",
"responseMode": "onReceived",
"responseData": ""
},
"id": "node-wh-02",
"name": "Webhook Twilio Respuestas",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "// Twilio envia form-urlencoded. Extraemos Body y From.\nconst body = $input.first().json.body;\n\n// From llega como 'whatsapp:+5493624777801' -> extraemos solo el numero\nconst fromRaw = body.From || '';\nconst celular = fromRaw.replace('whatsapp:+', '').replace('whatsapp:', '').replace('+', '');\n\n// Mensaje en minusculas para el switch\nconst mensaje = (body.Body || '').toLowerCase().trim();\n\n// Fecha de hoy y manana para buscar el turno activo\nconst hoy = new Date();\nconst manana = new Date(hoy);\nmanana.setDate(manana.getDate() + 1);\n\nconst fmt = d => d.toISOString().split('T')[0];\n\nreturn [{\n json: {\n celular,\n mensaje,\n from_raw: fromRaw,\n fecha_desde: fmt(hoy),\n fecha_hasta: fmt(manana)\n }\n}];"
},
"id": "node-code-02",
"name": "Extraer datos",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"url": "=REEMPLAZAR_CON_SUPABASE_URL/rest/v1/turnos?select=id,estado,fecha,hora_inicio,paciente:pacientes!inner(id,celular)&paciente.celular=eq.{{ $json.celular }}&fecha=gte.{{ $json.fecha_desde }}&fecha=lte.{{ $json.fecha_hasta }}&estado=in.(reservado,confirmado,en_sala)&limit=1",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "REEMPLAZAR_CON_SUPABASE_SERVICE_ROLE_KEY"
},
{
"name": "Authorization",
"value": "<redacted-credential>"
}
]
},
"options": {}
},
"id": "node-supa-find",
"name": "Buscar turno en Supabase",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
680,
300
]
},
{
"parameters": {
"jsCode": "// Combina el turno encontrado con los datos del paso anterior\nconst turno = $input.first().json[0] || null;\nconst prev = $('Extraer datos').first().json;\n\nif (!turno) {\n return [{ json: { turno_found: false, mensaje: prev.mensaje, from_raw: prev.from_raw } }];\n}\n\nreturn [{\n json: {\n turno_found: true,\n turno_id: turno.id,\n estado_actual: turno.estado,\n mensaje: prev.mensaje,\n from_raw: prev.from_raw,\n celular: prev.celular\n }\n}];"
},
"id": "node-code-03",
"name": "Combinar turno + mensaje",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-found",
"leftValue": "={{ $json.turno_found }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
},
"id": "node-if-found",
"name": "Turno encontrado?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1120,
300
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.mensaje }}",
"rightValue": "confirmo el turno.",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "confirmar"
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.mensaje }}",
"rightValue": "cancelar turno",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "cancelar"
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.mensaje }}",
"rightValue": "reprogramar turno",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "reagendar"
}
]
},
"options": {}
},
"id": "node-switch",
"name": "Switch accion",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
1340,
200
]
},
{
"parameters": {
"url": "=REEMPLAZAR_CON_SUPABASE_URL/rest/v1/turnos?id=eq.{{ $json.turno_id }}",
"httpMethod": "PATCH",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "REEMPLAZAR_CON_SUPABASE_SERVICE_ROLE_KEY"
},
{
"name": "Authorization",
"value": "<redacted-credential>"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Prefer",
"value": "return=minimal"
}
]
},
"sendBody": true,
"contentType": "json",
"body": "={ \"estado\": \"confirmado\" }",
"options": {}
},
"id": "node-supa-confirm",
"name": "Supabase: confirmar turno",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1560,
100
]
},
{
"parameters": {
"url": "=REEMPLAZAR_CON_SUPABASE_URL/rest/v1/turnos?id=eq.{{ $json.turno_id }}",
"httpMethod": "PATCH",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "REEMPLAZAR_CON_SUPABASE_SERVICE_ROLE_KEY"
},
{
"name": "Authorization",
"value": "<redacted-credential>"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Prefer",
"value": "return=minimal"
}
]
},
"sendBody": true,
"contentType": "json",
"body": "={ \"estado\": \"cancelado\", \"motivo_cancelacion\": \"por_paciente\" }",
"options": {}
},
"id": "node-supa-cancel",
"name": "Supabase: cancelar turno",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1560,
260
]
},
{
"parameters": {
"url": "https://api.twilio.com/2010-04-01/Accounts/REEMPLAZAR_CON_ACCOUNT_SID/Messages.json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "From",
"value": "whatsapp:+5493625456570"
},
{
"name": "To",
"value": "={{ $('Combinar turno + mensaje').first().json.from_raw }}"
},
{
"name": "Body",
"value": "\u2705 \u00a1Gracias! Tu turno est\u00e1 confirmado. Te esperamos \ud83d\ude4c"
}
]
},
"options": {}
},
"id": "node-reply-confirm",
"name": "WA: respuesta confirmado",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1780,
100
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "https://api.twilio.com/2010-04-01/Accounts/REEMPLAZAR_CON_ACCOUNT_SID/Messages.json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "From",
"value": "whatsapp:+5493625456570"
},
{
"name": "To",
"value": "={{ $('Combinar turno + mensaje').first().json.from_raw }}"
},
{
"name": "Body",
"value": "\u274c Entendemos, tu turno fue cancelado. Si quer\u00e9s sacar uno nuevo escribinos al +543624955955."
}
]
},
"options": {}
},
"id": "node-reply-cancel",
"name": "WA: respuesta cancelado",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1780,
260
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "https://api.twilio.com/2010-04-01/Accounts/REEMPLAZAR_CON_ACCOUNT_SID/Messages.json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "From",
"value": "whatsapp:+5493625456570"
},
{
"name": "To",
"value": "={{ $('Combinar turno + mensaje').first().json.from_raw }}"
},
{
"name": "Body",
"value": "\ud83d\udcc5 Claro, para reagendar escribinos directamente al +543624955955 y te ayudamos \ud83d\ude0a"
}
]
},
"options": {}
},
"id": "node-reply-reagendar",
"name": "WA: respuesta reagendar",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
1780,
420
],
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Webhook Twilio Respuestas": {
"main": [
[
{
"node": "Extraer datos",
"type": "main",
"index": 0
}
]
]
},
"Extraer datos": {
"main": [
[
{
"node": "Buscar turno en Supabase",
"type": "main",
"index": 0
}
]
]
},
"Buscar turno en Supabase": {
"main": [
[
{
"node": "Combinar turno + mensaje",
"type": "main",
"index": 0
}
]
]
},
"Combinar turno + mensaje": {
"main": [
[
{
"node": "Turno encontrado?",
"type": "main",
"index": 0
}
]
]
},
"Turno encontrado?": {
"main": [
[
{
"node": "Switch accion",
"type": "main",
"index": 0
}
],
[]
]
},
"Switch accion": {
"confirmar": [
[
{
"node": "Supabase: confirmar turno",
"type": "main",
"index": 0
}
]
],
"cancelar": [
[
{
"node": "Supabase: cancelar turno",
"type": "main",
"index": 0
}
]
],
"reagendar": [
[
{
"node": "WA: respuesta reagendar",
"type": "main",
"index": 0
}
]
]
},
"Supabase: confirmar turno": {
"main": [
[
{
"node": "WA: respuesta confirmado",
"type": "main",
"index": 0
}
]
]
},
"Supabase: cancelar turno": {
"main": [
[
{
"node": "WA: respuesta cancelado",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
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.
httpBasicAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Vitalis - Respuestas WhatsApp Twilio. Uses httpRequest. Webhook trigger; 11 nodes.
Source: https://github.com/gkovalek/agendavitalis/blob/main/n8n/workflow-2-respuestas-paciente.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Flujowhatsapp. Uses @aldinokemal2104/n8n-nodes-gowa, postgres, httpRequest. Webhook trigger; 65 nodes.
HR teams, IT Operations, and System Administrators managing employee onboarding at scale. It’s perfect if you use Odoo 18 to trigger account requests and need Redmine + GitLab accounts created instant
This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS
WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.
Backbrief: transcripts (Zoom webhook -> Slack + vault). Uses httpRequest, slack. Webhook trigger; 52 nodes.