Gestión de Webhooks
Endpoints para administrar tus webhooks: listar, actualizar, probar, ver logs y eliminar.
Listar Webhooks
Obtén todos los webhooks configurados.
curl -X GET https://api.whaapy.com/user-webhooks \
-H "Authorization: Bearer wha_TU_API_KEY"
Response:
{
"data": [
{
"id": "wh-uuid",
"name": "Mi Webhook",
"url": "https://mi-servidor.com/webhooks",
"events": ["message.received"],
"isActive": true,
"failureCount": 0,
"createdAt": "2025-01-15T10:00:00Z"
}
]
}
Actualizar Webhook
Modifica los eventos o estado de un webhook.
curl -X PATCH https://api.whaapy.com/user-webhooks/<id> \
-H "Authorization: Bearer wha_TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": ["message.received", "message.sent"],
"isActive": true
}'
| Campo | Tipo | Descripción |
|---|
name | string | Nuevo nombre |
url | string | Nueva URL |
events | string[] | Nueva lista de eventos |
isActive | boolean | Activar/desactivar |
Probar Webhook
Envía un evento de prueba para verificar tu endpoint.
curl -X POST https://api.whaapy.com/user-webhooks/<id>/test \
-H "Authorization: Bearer wha_TU_API_KEY"
Response:
{
"success": true,
"message": "Test webhook sent successfully",
"data": {
"status": 200,
"duration_ms": 150,
"response_preview": "{\"received\":true}"
}
}
Usa el endpoint de test para verificar que tu servidor responde correctamente antes de activar el webhook.
Ver Logs
Obtén el historial de entregas de un webhook.
curl -X GET "https://api.whaapy.com/user-webhooks/<id>/logs?limit=50" \
-H "Authorization: Bearer wha_TU_API_KEY"
Response:
{
"data": [
{
"id": "log-uuid",
"event": "message.received",
"status": 200,
"duration_ms": 120,
"timestamp": "2025-01-15T10:30:00Z",
"error": null
},
{
"id": "log-uuid-2",
"event": "message.sent",
"status": 500,
"duration_ms": 30000,
"timestamp": "2025-01-15T10:31:00Z",
"error": "Connection timeout"
}
]
}
Eliminar Webhook
curl -X DELETE https://api.whaapy.com/user-webhooks/<id> \
-H "Authorization: Bearer wha_TU_API_KEY"
Política de Reintentos
Cuando tu endpoint falla, Whaapy reintenta automáticamente:
| Intento | Delay | Tiempo total |
|---|
| 1 | Inmediato | 0s |
| 2 | 2 segundos | 2s |
| 3 | 4 segundos | 6s |
| 4 | 8 segundos | 14s |
Máximo 3 reintentos con backoff exponencial. Timeout por request: 30 segundos.
Desactivación Automática
Si un webhook falla 10 veces consecutivas, se desactiva automáticamente para proteger ambos sistemas.
Para reactivarlo:
curl -X PATCH https://api.whaapy.com/user-webhooks/<id> \
-H "Authorization: Bearer wha_TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"isActive": true}'
Antes de reactivar, verifica que tu endpoint esté funcionando correctamente.
Mejores Prácticas
1. Responde Rápido
Tu endpoint debe responder en menos de 30 segundos. Procesa async si necesitas hacer trabajo pesado.
app.post('/webhook', async (req, res) => {
// Responde inmediatamente
res.json({ received: true });
// Procesa después (async)
await processWebhook(req.body).catch(console.error);
});
from threading import Thread
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.get_json()
# Responde inmediatamente
response = jsonify({'received': True})
# Procesa en background
Thread(target=process_webhook, args=(payload,)).start()
return response
2. Implementa Idempotencia
Los webhooks pueden llegar más de una vez. Usa el timestamp y evento para detectar duplicados.
const processedEvents = new Set();
app.post('/webhook', (req, res) => {
const eventId = `${req.body.event}-${req.body.timestamp}`;
if (processedEvents.has(eventId)) {
return res.json({ received: true, duplicate: true });
}
processedEvents.add(eventId);
// Procesar...
res.json({ received: true });
});
En producción, usa Redis o una base de datos en lugar de un Set en memoria.
3. Verifica la Firma
Siempre verifica la firma HMAC antes de procesar. Ver Seguridad.
4. Usa HTTPS
Los webhooks solo se envían a endpoints HTTPS. Para desarrollo local, usa:
5. Loggea para Debugging
app.post('/webhook', (req, res) => {
console.log('Webhook received:', {
event: req.body.event,
timestamp: req.headers['x-webhook-timestamp'],
id: req.headers['x-webhook-id'],
});
// Procesar...
});
Ejemplo Completo: Integración con CRM
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WHAAPY_WEBHOOK_SECRET;
const CRM_API = 'https://mi-crm.com/api';
function verifySignature(payload, signature) {
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post('/webhooks/whaapy', async (req, res) => {
// 1. Verificar firma
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// 2. Responder inmediatamente
res.json({ received: true });
// 3. Procesar según evento
const { event, data } = req.body;
try {
switch (event) {
case 'message.received':
// Extraer texto del formato Meta
const text = data.message?.text?.body || '[Media]';
await axios.post(`${CRM_API}/activities`, {
type: 'whatsapp_message',
contact_phone: data.message.from,
content: text,
direction: 'inbound',
whaapy_id: data.whaapy_message_id,
});
break;
case 'contact.created':
await axios.post(`${CRM_API}/contacts`, {
phone: data.phone_number,
name: data.name,
source: 'whaapy',
});
break;
case 'conversation.closed':
await axios.patch(`${CRM_API}/deals`, {
phone: data.phone_number,
status: 'contacted',
});
break;
}
} catch (error) {
console.error('Error procesando webhook:', error.message);
}
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
Recursos Adicionales