Webhook para leads y citas: envía solicitudes a Zapier, Make, n8n o tu CRM
Webhook para leads y citas
Un webhook envía cada nueva solicitud al instante a la dirección que usted elija. Así, los leads y las citas llegan directamente a Zapier, Make, n8n o a su propio CRM, por ejemplo para abrir un ticket o avisar por correo a su equipo de ventas.
El webhook está disponible a partir del plan Standard, consulte la página de precios.
Configuración
- Abra Panel → su asistente → Funciones.
- En la lista, elija Enviar automáticamente (grupo Ganar clientes). Allí encontrará la sección Webhook.
- Introduzca la dirección, por ejemplo la URL del «Catch Hook» de Zapier, y haga clic en Guardar.
- Copie la Clave secreta. Solo se muestra esta vez. Con Nueva clave puede crear otra si la necesita.
- Elija qué se envía: Nuevas solicitudes de contacto, Nuevas citas o ambas.
- Con Probar enviamos una solicitud de ejemplo a su dirección.
La dirección debe empezar por https://, ser accesible públicamente y usar el puerto 443 o 8443. Rechazamos las direcciones de su propia red (por ejemplo localhost o 192.168.…).
Eventos
| Evento | Cuándo |
|---|---|
lead.created | Se ha guardado un lead, desde el chat, una llamada o un formulario de la Action Bar. |
booking.created | Se ha reservado una cita. |
Ejemplo: nuevo lead
{
"id": "7a05fd6b-3b54-4235-b76e-7695c4ab13a3",
"event": "lead.created",
"createdAt": "2026-10-23T15:11:28.895Z",
"data": {
"leadId": "51f7f1e3-3e2f-471b-ade6-90959a5d3724",
"source": "chat",
"name": "Lucía Ejemplo",
"email": "lucia@example.com",
"phone": "+34 910 000 000",
"interest": "Presupuesto para una bomba de calor",
"language": "es",
"fields": { "Empresa": "Ejemplo S.L." },
"sessionId": "861f9c24-11ab-4352-b326-5670b0196fc0",
"createdAt": "2026-10-23T15:11:28.742Z"
}
}
source es chat, phone o form. Los campos sin valor no se incluyen. fields contiene sus datos adicionales, con el nombre del campo como clave. Si el visitante pide que le llamen, se añade callback con day y time; en los formularios se añade formName.
Ejemplo: nueva cita
{
"id": "0c8f2d0e-6f1a-4a43-9a0b-2f9a3c1d5e77",
"event": "booking.created",
"createdAt": "2026-10-23T15:20:04.112Z",
"data": {
"bookingId": "e3f82cb1-4f6a-4d6e-9c55-0d1a2b3c4d5e",
"source": "card",
"appointmentType": { "id": "consulta", "title": "Consulta gratuita", "durationMinutes": 30 },
"start": "2026-10-28T14:00",
"end": "2026-10-28T14:30",
"startUtc": "2026-10-28T13:00:00.000Z",
"endUtc": "2026-10-28T13:30:00.000Z",
"timezone": "Europe/Madrid",
"name": "Javier Ejemplo",
"email": "javier@example.com",
"fields": { "Empresa": "Reformas Ejemplo S.L." },
"createdAt": "2026-10-23T15:20:04.050Z"
}
}
start y end son la hora local en timezone; startUtc y endUtc, los mismos momentos en UTC. source es card (reserva con la tarjeta de citas del chat), chat o phone. Los campos sin valor no se incluyen: name (si el nombre no se preguntó o no se indicó), email, phone, note (el motivo), meetingLink (enlace de videollamada, solo con Google Calendar) y sessionId. fields contiene las respuestas a los datos adicionales de Reservar citas, con el nombre del campo como clave.
Cabeceras
| Cabecera | Contenido |
|---|---|
X-Webhook-Id | ID único del envío, igual que el campo id. Sirve para detectar envíos duplicados. |
X-Webhook-Event | lead.created o booking.created |
X-Webhook-Timestamp | Momento del envío en segundos desde 1970 |
X-Webhook-Signature | sha256= más HMAC-SHA256 sobre timestamp.rawBody con su clave secreta |
Comprobar la firma
Compruebe la firma antes de usar los datos. Use el cuerpo original de la solicitud sin modificar, no un JSON generado de nuevo.
Node.js:
import { createHmac, timingSafeEqual } from 'node:crypto'
export function isValidWebhook(rawBody, headers, secret) {
const timestamp = headers['x-webhook-timestamp']
const expected = 'sha256=' + createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
const received = String(headers['x-webhook-signature'] || '')
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300
return fresh && received.length === expected.length && timingSafeEqual(Buffer.from(received), Buffer.from(expected))
}
PHP:
$raw = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $raw, $secret);
if (!hash_equals($expected, $received) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$event = json_decode($raw, true);
En Zapier o Make puede prescindir de la comprobación de la firma, siempre que la dirección se mantenga en secreto.
Respuesta y reintentos
- Responda con un estado 2xx en cuanto haya recibido los datos. No leemos el contenido de su respuesta.
- Esperamos como máximo 5 segundos.
- Si se agota el tiempo, hay un error de red o un estado 429 o 5xx, lo intentamos de nuevo tras 1 y tras 5 segundos, es decir, tres veces como máximo.
- Los demás errores (por ejemplo 404) no se reintentan. No seguimos redirecciones.
- En el Panel verá el resultado del último envío en Último envío.
Si su sistema no responde, no se pierde ningún lead: siempre se guarda primero en el Panel de leads.
