OpenClaw Webhooks — Integración con agentes IA
Skill de referencia para recibir y verificar webhooks del gateway OpenClaw, con ejemplos listos en Express y FastAPI para construir servicios externos que reaccionen a eventos de agentes IA.
Descarga abierta · sin registro · para Node.js, Python, Express
// Generated with: openclaw-webhooks skill // https://github.com/hookdeck/webhook-skills // // FlowDesk CRM — Webhook Handler para Agentes IA OpenClaw // Cliente: FlowDesk CRM (SaaS B2B para PYMEs) // Generado por CULTIVA IA — https://cultivaia.com // ----------------------------------------------------------
const express = require('express'); const crypto = require('crypto');
const app = express(); const PORT = process.env.PORT || 3000;
// ─── 1. VERIFICACIÓN DE TOKEN ─────────────────────────────────────────────────
/**
- Verifica el token Bearer enviado por OpenClaw Gateway.
- Soporta dos formatos de cabecera:
- Authorization: Bearer
- x-openclaw-token:
- Usa timingSafeEqual para prevenir timing attacks. */ function verifyOpenClawWebhook(authHeader, xTokenHeader, secret) { const token = extractToken(authHeader, xTokenHeader); if (!token || !secret) return false;
try { return crypto.timingSafeEqual( Buffer.from(token), Buffer.from(secret) ); } catch { return false; } }
function extractToken(authHeader, xTokenHeader) { if (xTokenHeader) return xTokenHeader; if (authHeader && authHeader.startsWith('Bearer ')) return authHeader.slice(7); return null; }
// ─── 2. LOGGER ESTRUCTURADO ───────────────────────────────────────────────────
function log(level, event, data = {}) { console.log(JSON.stringify({ ts: new Date().toISOString(), level, service: 'flowdesk-openclaw-handler', event, ...data, })); }
// ─── 3. PROCESAMIENTO DE EVENTOS (ASYNC) ─────────────────────────────────────
/**
- Procesa un evento de agente IA de forma asíncrona.
- FlowDesk lo usa para:
- Generar respuestas borrador de soporte al cliente
- Resumir conversaciones largas
- Enrutar tickets según prioridad detectada por la IA */ async function processAgentEvent(payload) { const { message, name, agentId, sessionKey, wakeMode, channel, to } = payload;
log('info', 'agent.processing', { agentId: agentId || 'default', name: name || 'FlowDesk Agent', sessionKey, wakeMode: wakeMode || 'now', deliveryChannel: channel || 'slack', recipient: to, messagePreview: message?.slice(0, 80), });
// Aquí iría la lógica de negocio de FlowDesk: // - Consultar ticket en BD por sessionKey // - Enriquecer el mensaje con contexto del cliente // - Almacenar el jobId de OpenClaw para trazabilidad
log('info', 'agent.queued', { sessionKey, note: 'Agente IA encolado — respuesta será entregada via Slack al equipo de soporte', }); }
/**
- Procesa un evento de wake (sistema).
- FlowDesk lo usa para:
- Notificar al agente de nuevos correos entrantes
- Alertar sobre SLAs próximos a vencer
- Refrescar contexto del cliente en la sesión del agente */ async function processWakeEvent(payload) { const { text, mode } = payload;
log('info', 'wake.processing', { mode: mode || 'now', eventText: text, });
// Lógica: registrar el evento en tabla agent_events para auditoría
log('info', 'wake.recorded', { note: 'Evento sistema registrado en BD' });
}
// ─── 4. RUTAS WEBHOOK ─────────────────────────────────────────────────────────
// Middleware de autenticación reutilizable function authenticateOpenClaw(req, res, next) { const authHeader = req.headers['authorization']; const xToken = req.headers['x-openclaw-token']; const secret = process.env.OPENCLAW_HOOK_TOKEN;
if (!verifyOpenClawWebhook(authHeader, xToken, secret)) { log('warn', 'auth.failed', { ip: req.ip, path: req.path, hasAuth: !!authHeader, hasXToken: !!xToken, }); return res.status(401).json({ error: 'Token inválido o ausente' }); }
next(); }
/**
POST /hooks/agent
Recibe solicitudes para ejecutar un turno del agente IA.
OpenClaw espera respuesta 202 Accepted rápida; el trabajo es async.
Payload esperado:
{
"message": "El cliente Pablo García reporta que no puede exportar facturas PDF",
"name": "SoporteTicket",
"agentId": "flowdesk-support-agent",
"sessionKey": "ticket:FD-4821",
"wakeMode": "now",
"deliver": true,
"channel": "slack",
"to": "#soporte-ia",
"model": "openai/gpt-4o-mini",
"thinking": "medium",
"timeoutSeconds": 60
} */ app.post('/hooks/agent', express.json({ limit: '256kb' }), authenticateOpenClaw, async (req, res) => { const payload = req.body;
// Validación básica del payload if (!payload.message) { log('warn', 'agent.invalid_payload', { reason: 'message requerido' }); return res.status(400).json({ error: 'Campo "message" requerido' }); }
// Responder inmediatamente (OpenClaw no espera resultado, solo ACK) res.status(202).json({ received: true, queued: true });
// Procesar en background (no bloquea la respuesta HTTP) processAgentEvent(payload).catch(err => { log('error', 'agent.processing_error', { message: err.message }); }); } );
/**
POST /hooks/wake
Encola un evento de sistema para que el agente lo procese en su próximo ciclo.
OpenClaw espera 200 OK.
Payload esperado:
{
"text": "Nuevo ticket creado: FD-4821 — prioridad alta",
"mode": "now"
} */ app.post('/hooks/wake', express.json({ limit: '64kb' }), authenticateOpenClaw, async (req, res) => { const payload = req.body;
if (!payload.text) { log('warn', 'wake.invalid_payload', { reason: 'text requerido' }); return res.status(400).json({ error: 'Campo "text" requerido' }); }
// Responder inmediatamente res.status(200).json({ received: true });
// Procesar en background processWakeEvent(payload).catch(err => { log('error', 'wake.processing_error', { message: err.message }); }); } );
// ─── 5. HEALTH CHECK ─────────────────────────────────────────────────────────
app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'flowdesk-openclaw-handler', version: '1.0.0', endpoints: ['/hooks/agent', '/hooks/wake'], }); });
// ─── 6. ARRANQUE ─────────────────────────────────────────────────────────────
app.listen(PORT, () => { log('info', 'server.started', { port: PORT }); if (!process.env.OPENCLAW_HOOK_TOKEN) { log('warn', 'config.missing', { note: 'OPENCLAW_HOOK_TOKEN no configurado — los webhooks serán rechazados', }); } });
module.exports = app; // Para testing
/* ───────────────────────────────────────────────────────────────── VARIABLES DE ENTORNO (.env) ─────────────────────────────────────────────────────────────────
OPENCLAW_HOOK_TOKEN=flowdesk_oc_prod_x7k2m9n4p1q8r5s3 PORT=3000
───────────────────────────────────────────────────────────────── DESARROLLO LOCAL CON TUNNEL ─────────────────────────────────────────────────────────────────
Instalar Hookdeck CLI (una vez)
npm install -g hookdeck-cli
Arrancar el servidor
node server.js
En otra terminal, crear el tunnel
npx hookdeck-cli listen 3000 openclaw --path /hooks/agent
Hookdeck dará una URL pública tipo:
https://hkdk.events/xxxxxxxx
→ Configúrala como webhook URL en el panel de OpenClaw Gateway
───────────────────────────────────────────────────────────────── EJEMPLO CURL — Disparar agente de soporte ─────────────────────────────────────────────────────────────────
curl -X POST http://localhost:3000/hooks/agent
-H "Content-Type: application/json"
-H "Authorization: Bearer flowdesk_oc_prod_x7k2m9n4p1q8r5s3"
-d '{
"message": "El cliente Pablo García (ticket FD-4821) no puede exportar facturas PDF. Sistema: MacOS 14, Chrome 124.",
"name": "SoporteTicket",
"agentId": "flowdesk-support-agent",
"sessionKey": "ticket:FD-4821",
"wakeMode": "now",
"deliver": true,
"channel": "slack",
"to": "#soporte-ia",
"model": "openai/gpt-4o-mini",
"thinking": "medium",
"timeoutSeconds": 60
}'
Respuesta esperada: HTTP 202
{ "received": true, "queued": true }
───────────────────────────────────────────────────────────────── EJEMPLO CURL — Evento wake (nuevo ticket) ─────────────────────────────────────────────────────────────────
curl -X POST http://localhost:3000/hooks/wake
-H "Content-Type: application/json"
-H "x-openclaw-token: flowdesk_oc_prod_x7k2m9n4p1q8r5s3"
-d '{
"text": "Nuevo ticket creado: FD-4822 — cliente Enterprise, prioridad ALTA, asignado a soporte-ia",
"mode": "now"
}'
Respuesta esperada: HTTP 200
{ "received": true }
───────────────────────────────────────────────────────────────── */
// qué_hace
Proporciona código listo para verificar tokens y manejar payloads de webhooks enviados por el gateway de agentes IA OpenClaw.
// cómo_lo_hace
Implementa verificación de token mediante comparación segura (timingSafeEqual / hmac.compare_digest) en Express y FastAPI, con tablas de referencia de endpoints, campos y códigos de respuesta.
// ejemplo_de_uso
Úsala cuando construyes un agente IA que necesita recibir notificaciones asíncronas de OpenClaw. Ej.: verificas el token y procesas el payload de finalización de tarea en tu endpoint FastAPI.
// plataformas
// opiniones_de_la_comunidad
Opiniones
Cargando opiniones…
// pase_cultiva_ia
Llévate todo el arsenal con el Pase
Todas las skills, prompts y automatizaciones del catálogo en un único archivo, listas para usar: un pago, acceso de por vida y las novedades que añadamos. Sin suscripción.
Pago único · IVA incluido · pago seguro con Stripe.
Acceso inmediato · si no es lo que esperabas, te devolvemos los 10 €.