Skip to main content

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
  }'
CampoTipoDescripción
namestringNuevo nombre
urlstringNueva URL
eventsstring[]Nueva lista de eventos
isActivebooleanActivar/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:
IntentoDelayTiempo total
1Inmediato0s
22 segundos2s
34 segundos6s
48 segundos14s
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);
});

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