Outbound Webhooks
Crimoo puede notificar sistemas externos (CRMs, Zapier, n8n, Make, etc.) en tiempo real cuando identifica o actualiza contactos. Cada webhook es una suscripción configurable a uno o más tipos de eventos.
Qué hace cada tipo de evento
contact.identified — Contacto Identificado
Se dispara la primera vez que Crimoo asocia una identidad real a un visitante. Ocurre cuando:
- El visitante envía un formulario capturado por una capture rule
- Crimoo extrae el email (u otro PII), hashea y crea un nuevo registro de contacto en PostgreSQL
- Es la señal de que "este visitante anónimo ahora tiene nombre e email"
Caso de uso típico: Enviar el nuevo lead a un CRM externo (HubSpot, Salesforce, Pipedrive) en el momento exacto en que se identifica.
{
"eventType": "contact.identified",
"data": {
"contact": {
"id": "uuid",
"email": "user@example.com",
"fields": { "name": "Juan", "phone": "+34600000000" }
}
}
}
contact.updated — Contacto Actualizado
Se dispara cuando un contacto ya existente recibe nueva información. Ocurre cuando:
- El mismo visitante vuelve a enviar un formulario con campos distintos o adicionales
- Crimoo detecta el contacto por hash de email o por cookie
_crimoo_uidy actualiza sus campos - El payload incluye
previousFieldspara comparar qué cambió
Caso de uso típico: Sincronizar actualizaciones de perfil a un sistema externo, o disparar un workflow cuando el contacto agrega su teléfono tras haber dado solo el email.
{
"eventType": "contact.updated",
"data": {
"contact": {
"id": "uuid",
"email": "user@example.com",
"fields": { "name": "Juan", "phone": "+34600000000", "company": "Acme" }
},
"previousFields": { "name": "Juan" }
}
}
contact.merged (próximamente)
Se dispara cuando dos contactos duplicados se fusionan en uno solo. El payload incluirá el ID del contacto eliminado.
contact.deleted (próximamente)
Se dispara cuando un contacto es eliminado del CRM.
Flujo general
Payload completo
Headers enviados:
Content-Type: application/json
X-Webhook-Event: contact.identified
X-Delivery-Id: 550e8400-e29b-41d4-a716-446655440000
X-Webhook-Signature: sha256=<hmac_hex>
User-Agent: Crimoo-Webhook/1.0
Body:
{
"deliveryId": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "contact.identified",
"timestamp": "2026-04-07T14:23:01.000Z",
"gtmContainerId": "GTM-XXXXXXX",
"data": {
"contact": { ... },
"previousFields": { ... }
}
}
Idempotencia:
deliveryIdes el mismo UUID en todos los reintentos del mismo evento. Úsalo para deduplicar en el receptor.
Verificar la firma HMAC
El sistema firma el body con el secret del webhook usando HMAC-SHA256. Para validarlo en el receptor:
import { createHmac, timingSafeEqual } from 'crypto';
const expected = `sha256=${createHmac('sha256', webhookSecret).update(rawBody).digest('hex')}`;
const received = req.headers['x-webhook-signature'];
const valid = timingSafeEqual(Buffer.from(expected), Buffer.from(received));
Usa
timingSafeEqualpara evitar timing attacks. El secret se muestra una sola vez al crear el webhook.
Entrega con reintentos y circuit breaker
Tiempos de reintento
| Intento | Demora |
|---|---|
| 1 | Inmediato |
| 2 | +10 segundos |
| 3 | +30 segundos |
| 4 | +90 segundos |
| 5 | +270 segundos (~4.5 min) |
Circuit breaker
Cuando el circuit breaker se activa, el webhook aparece con alerta en la UI y deja de recibir eventos hasta que se resetee manualmente.
Configuración
| Campo | Descripción |
|---|---|
| Nombre | Identificador legible |
| URL | Endpoint HTTPS del receptor |
| Eventos | contact.identified, contact.updated (multi-selección) |
| Rate limit | Peticiones por minuto (default 60, token bucket por webhook) |
API REST
Base: /api/crm/webhooks/:gtmContainerId
| Método | Ruta | Descripción |
|---|---|---|
| GET | / | Listar webhooks |
| POST | / | Crear (devuelve secret completo, solo una vez) |
| GET | /:id | Obtener webhook (secret enmascarado) |
| PUT | /:id | Actualizar |
| DELETE | /:id | Eliminar |
| POST | /:id/test | Enviar entrega de prueba |
| GET | /:id/deliveries | Historial de entregas (últimos 50, TTL 7 días) |
| POST | /:id/reset-circuit | Resetear circuit breaker |