Ir al contenido principal
Zenovay
Pro Plan12 minutesIntermedio

Webhooks

Configura webhooks salientes para recibir notificaciones en tiempo real de Zenovay cuando ocurran eventos de la plataforma, y aprende cómo Zenovay gestiona internamente los webhooks de pago entrantes.

webhooksapiintegrationnotificationsautomation
Última actualización:
Pro Plan

Configura webhooks salientes para recibir notificaciones en tiempo real de Zenovay cuando ocurran eventos de la plataforma, y aprende cómo Zenovay gestiona internamente los webhooks de pago entrantes.

Webhooks salientes

Zenovay admite webhooks salientes configurables por el usuario para que tus servicios puedan reaccionar a los eventos de la plataforma a medida que ocurren, en lugar de sondear la API en busca de cambios.

Disponibilidad por plan

La gestión de webhooks salientes a través de la API requiere un token de API personal, y los tokens de API son una característica de pago. Están disponibles en el plan Pro y superiores (los planes Free no pueden crear tokens de API). Crea un token en Settings → Account → Security & access (app.zenovay.com/settings/account/security). Los webhooks están limitados al equipo al que pertenece ese token.

Creación de un webhook

Los webhooks se gestionan en /v1/cli/mutate/webhooks en la API de Zenovay. Pasa la url de destino (debe ser https://) y al menos un tipo de evento. Crea uno con una petición POST:

curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://yoursite.com/zenovay-hook","events":["traffic_spike"]}'

La respuesta incluye el id del webhook y un secret de firma. El secret se devuelve solo en la creación — guárdalo inmediatamente en un lugar seguro. Si lo pierdes, rota el secret (ver más abajo); el original no se puede recuperar.

Listado de webhooks

curl https://api.zenovay.com/v1/cli/mutate/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN"

Verificación de firmas de webhook

Cada entrega de webhook se firma con HMAC utilizando el secret de firma obtenido en la creación. Verifica la firma en tu endpoint antes de confiar en el payload, y utiliza una comparación de tiempo constante para que la verificación no sea vulnerable a ataques de temporización:

import crypto from 'crypto';

function verifyZenovayWebhook(rawBody, signatureHeader, secret) {
  // The signature header value is prefixed with the algorithm,
  // e.g. "sha256=<hex>". Strip the prefix before comparing.
  const received = (signatureHeader || '').replace(/^sha256=/, '');

  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  // timingSafeEqual throws if the buffers differ in length, so
  // length-check first, then compare in constant time.
  if (expected.length !== received.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(received)
  );
}

Valida siempre el cuerpo de la petición en bruto (los bytes exactos recibidos), no una versión reserializada, para que la firma que calcules coincida con la que calculó Zenovay.

El nombre exacto del encabezado que transporta la firma está documentado en la Referencia de la API REST.

Probar un webhook

Envía una entrega de prueba sintética para confirmar que tu endpoint está correctamente configurado. La respuesta incluye el resultado del intento de entrega (estado HTTP de tu endpoint y duración):

curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/test \
  -H "Authorization: Bearer YOUR_TOKEN"

Rotación del secret de firma

Si un secret se filtra o quieres rotarlo periódicamente, rótalo. El nuevo secret se devuelve solo una vez en la respuesta:

curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/rotate \
  -H "Authorization: Bearer YOUR_TOKEN"

Tras la rotación, actualiza tu endpoint para verificar con el nuevo secret. Las firmas antiguas dejan de validarse de inmediato.

Revocación de un webhook

curl -X DELETE https://api.zenovay.com/v1/cli/mutate/webhooks/{id} \
  -H "Authorization: Bearer YOUR_TOKEN"

Los webhooks revocados dejan de recibir entregas inmediatamente. La revocación no se puede deshacer.

Mejores prácticas

  • Responde con un 2xx lo más rápido posible. Confirma primero y luego procesa el evento en un trabajo en segundo plano.
  • Sé idempotente. Los reintentos de red pueden provocar que el mismo evento llegue más de una vez — indexa tu handler por el id del evento, no por la hora de recepción.
  • Verifica antes de confiar. Rechaza cualquier petición cuyo HMAC no se valide, y rechaza las peticiones cuyo timestamp esté muy fuera de una ventana aceptable.
  • Rota los secrets si alguien fuera del equipo ha tenido acceso a tu configuración o registros de webhooks.

Webhooks de pago entrantes

Zenovay también procesa webhooks entrantes de servicios externos para gestionar suscripciones e infraestructura. Estos se ejecutan dentro de la plataforma Zenovay y no requieren configuración por tu parte.

Fuentes de webhooks entrantes

FuentePropósito
StripeGestión de suscripciones, procesamiento de pagos, completación de checkout
Monitoreo de disponibilidadDisparadores de verificación de salud desde servicios externos

Alternativas por sondeo

Si los webhooks salientes no encajan con tu caso de uso (por ejemplo, necesitas agregados puntuales en lugar de un flujo de eventos), aún puedes crear integraciones en tiempo real sondeando la External API.

La External API también es una característica de pago — requiere una clave de API, y los planes Free no incluyen acceso API. Los endpoints a continuación devuelven la envoltura estándar { success, data, timestamp }, así que tu payload está bajo data.

Sondeo con la External API

const API_KEY = process.env.ZENOVAY_API_KEY;
const WEBSITE_ID = process.env.ZENOVAY_WEBSITE_ID;

async function checkAnalytics() {
  const response = await fetch(
    `https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}?range=24h`,
    {
      headers: { 'X-API-Key': API_KEY }
    }
  );

  const { data } = await response.json();

  if (data.summary.total_visitors > threshold) {
    await sendSlackNotification(data);
  }
}

// Poll every 5 minutes
setInterval(checkAnalytics, 5 * 60 * 1000);

El parámetro range acepta 24h, 7d, 30d, 90d o 1y (por defecto 7d).

Recuento de visitantes en vivo

Usa el endpoint público en vivo para verificar el recuento actual de visitantes sin una clave API:

async function getLiveVisitors(trackingCode) {
  const response = await fetch(
    `https://api.zenovay.com/e/live/${trackingCode}`
  );
  return await response.json();
}

Ejemplo de integración con Slack

Crea un informe programado que publique en Slack:

async function sendDailyReport() {
  const response = await fetch(
    `https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}?range=24h`,
    {
      headers: { 'X-API-Key': API_KEY }
    }
  );

  const { data } = await response.json();
  const { summary } = data;

  await fetch(SLACK_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: `Daily Analytics Report:\n` +
            `Visitors: ${summary.total_visitors}\n` +
            `Unique Visitors: ${summary.unique_visitors}\n` +
            `Page Views: ${summary.total_page_views}`
    })
  });
}

Ejemplo de integración con CRM

Sincroniza los datos de análisis con tu CRM de forma programada:

async function syncToCRM() {
  const response = await fetch(
    `https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}/visitors`,
    {
      headers: { 'X-API-Key': API_KEY }
    }
  );

  const { data } = await response.json();

  for (const visitor of data.visitors) {
    await crm.contacts.update({
      country: visitor.country_name,
      city: visitor.city,
      last_seen: visitor.visited_at
    });
  }
}

Límites de tasa para el sondeo

Al crear integraciones de sondeo, respeta los límites de tasa de la External API:

PlanSolicitudes/MinutoLímite mensual
Free101.000
Pro3010.000
Scale60100.000
Enterprise1201.000.000

Mejores prácticas de sondeo

  • Almacena en caché las respuestas de la API localmente para reducir la frecuencia de solicitudes
  • Usa intervalos de sondeo apropiados (se recomienda un mínimo de 5 minutos)
  • Monitorea el encabezado X-RateLimit-Remaining para evitar alcanzar los límites
  • Implementa retroceso exponencial si recibes respuestas 429

Próximos pasos

¿Fue útil este artículo?