Sync webhook con CRM
Mantén tu CRM sincronizado automáticamente con OptimoCMS mediante webhooks. Aprende a configurar webhooks, procesar payloads y verificar firmas.
Sync webhook con tu CRM
Los webhooks envían notificaciones en tiempo real a tu servidor cuando algo sucede en OptimoCMS — se envía un formulario, se realiza un pedido o se publica una página.
En este tutorial:
- Crear un webhook mediante el SDK
- Construir un servidor Express para recibir payloads
- Verificación criptográfica de firmas
- Procesar payloads y reenviarlos a un CRM
Requisitos previos
- Node.js 18+
npm install @optimocms/sdk express- Un endpoint públicamente accesible (usa ngrok para pruebas locales)
Paso 1 — Crear un webhook
SDK
import { OptimoCMS } from '@optimocms/sdk';
const client = new OptimoCMS({
apiKey: process.env.OPTIMOCMS_API_KEY!,
});
const webhook = await client.webhooks.create('site_abc123', {
url: 'https://tu-servidor.es/webhooks/optimocms',
events: ['form.submitted', 'order.created', 'booking.created'],
});
console.log(`Webhook creado: ${webhook.id}`);
console.log(`Secret: ${webhook.secret}`);REST
curl -X POST https://api.optimocms.com/v1/sites/$SITE_ID/webhooks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-servidor.es/webhooks/optimocms",
"events": ["form.submitted", "order.created", "booking.created"]
}'Paso 2 — Construir un endpoint webhook
Crea un servidor Express que recibe y procesa los payloads webhook:
import express from 'express';
import crypto from 'node:crypto';
const app = express();
const WEBHOOK_SECRET = process.env.OPTIMOCMS_WEBHOOK_SECRET!;
app.post(
'/webhooks/optimocms',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-optimocms-signature'] as string;
const timestamp = req.headers['x-optimocms-timestamp'] as string;
if (!verifySignature(req.body, signature, timestamp)) {
console.error('Firma de webhook inválida');
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
switch (event.type) {
case 'form.submitted':
handleFormSubmission(event.data);
break;
case 'order.created':
handleNewOrder(event.data);
break;
case 'booking.created':
handleNewBooking(event.data);
break;
default:
console.log(`Tipo de evento desconocido: ${event.type}`);
}
res.status(200).json({ received: true });
}
);
app.listen(3000, () => {
console.log('Servidor webhook ejecutándose en el puerto 3000');
});Paso 3 — Verificación de firmas
OptimoCMS firma cada webhook con HMAC-SHA256. Verifica siempre antes de procesar:
function verifySignature(
body: Buffer,
signature: string,
timestamp: string
): boolean {
if (!signature || !timestamp) return false;
const timestampMs = parseInt(timestamp, 10);
const ageMs = Date.now() - timestampMs;
if (ageMs > 5 * 60 * 1000) {
console.error(`Webhook demasiado antiguo: ${ageMs}ms`);
return false;
}
const payload = `${timestamp}.${body.toString()}`;
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
const expectedBuffer = Buffer.from(expected, 'hex');
const receivedBuffer = Buffer.from(signature, 'hex');
if (expectedBuffer.length !== receivedBuffer.length) return false;
return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);
}Paso 4 — Reenviar payloads al CRM
Ejemplo: reenviar datos de formulario a HubSpot CRM:
interface FormSubmission {
formId: string;
siteId: string;
fields: Record<string, string>;
submittedAt: string;
}
async function handleFormSubmission(data: FormSubmission): Promise<void> {
const { fields } = data;
const response = await fetch('https://api.hubapi.com/crm/v3/objects/contacts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.HUBSPOT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
properties: {
firstname: fields.firstName || fields.name?.split(' ')[0] || '',
lastname: fields.lastName || fields.name?.split(' ').slice(1).join(' ') || '',
email: fields.email,
phone: fields.phone || '',
company: fields.company || '',
hs_lead_status: 'NEW',
source: `OptimoCMS form: ${data.formId}`,
},
}),
});
if (!response.ok) {
const error = await response.text();
console.error(`Sync HubSpot fallida: ${error}`);
throw new Error(`CRM sync failed: ${response.status}`);
}
console.log(`✓ Contacto creado en HubSpot para ${fields.email}`);
}Eventos webhook disponibles
| Evento | Disparador |
|---|---|
form.submitted | Un visitante envía un formulario |
order.created | Nuevo pedido en la tienda |
order.updated | Cambio de estado del pedido |
booking.created | Nueva reserva |
booking.cancelled | Reserva cancelada |
page.created | Nueva página creada |
page.updated | Contenido de página modificado |
page.deleted | Página eliminada |
site.published | Sitio publicado en producción |
Buenas prácticas
- Siempre verificar la firma — Nunca confíes ciegamente en las peticiones entrantes
- Responder rápido con 200 — Procesa el payload de forma asíncrona si tarda
- Idempotencia — Usa el campo
idpara detectar duplicados - Tolerante a retries — OptimoCMS reintenta entregas fallidas automáticamente (máx. 5x)
- Logging — Registra cada webhook entrante para depuración
Siguientes pasos
- Referencia API: Webhooks — Documentación completa de la API de webhooks
- Pipeline CI/CD — Automatizar despliegues
- Crear un sitio de restaurante — Sitio de ejemplo con formularios
Automatización multi-sitio
Crea y gestiona decenas de sitios programáticamente con el SDK de OptimoCMS. Ideal para franquicias, agencias y plataformas white-label.
Pipeline CI/CD
Automatiza actualizaciones de contenido y publicación con GitHub Actions y el SDK de OptimoCMS. De staging a producción en un solo push.