← DocumentaciónPlataforma

Webhooks

Recibe eventos en tu sistema, HMAC + retries.

Cuando algo pasa en Replai — un mensaje entra, una sesión se conecta, un envío falla — firmamos un payload con HMAC-SHA256 y lo POSTeamos a tu endpoint. Si tu endpoint falla, reintentamos con backoff exponencial.

Eventos disponibles

EventoCuándo dispara
message.receivedLlegó un mensaje del cliente.
message.sentEl worker envió un outbound (bot o API).
message.deliveredWhatsApp confirmó entrega (2 checks).
message.readEl destinatario abrió el chat (2 checks azules).
message.failedEnvío falló tras todos los reintentos.
session.connectedSesión WhatsApp viva.
session.disconnectedSesión cayó (con reason).
session.qr_generatedQR listo para escanear.
session.logged_outWhatsApp invalidó las credenciales.

Crear un endpoint

Desde el dashboard → Webhooks → + Nuevo, o vía API:

curl -X POST https://app.replai.tech/api/v1/webhooks \
  -H "authorization: Bearer rk_live_..." \
  -H "content-type: application/json" \
  -d '{
    "name": "Mi sistema",
    "url": "https://mi-app.com/replai/webhook",
    "events": ["message.received", "message.failed"]
  }'

La respuesta contiene un secretguárdalo ahí mismo, nunca te lo volveremos a mostrar.

Verificar la firma

Cada delivery viene con dos headers:

x-replai-timestamp: 1747401123
x-replai-signature: <hex-sha256>

La firma es HMAC-SHA256 de {timestamp}.{rawBody} usando tu secret.

Node:

import { verifyWebhookSignature } from '@replai/sdk';

app.post('/replai/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const ok = verifyWebhookSignature({
    rawBody: req.body,                              // ← Buffer, NOT parsed JSON
    signatureHeader: req.header('x-replai-signature') ?? '',
    timestampHeader: req.header('x-replai-timestamp') ?? '',
    secret: process.env.WEBHOOK_SECRET!,
  });
  if (!ok) return res.status(401).send('bad signature');
  const event = JSON.parse(req.body.toString());
  // ... handle event ...
  res.send({ ok: true });
});

Python:

from replai import verify_webhook_signature

@app.post("/replai/webhook")
async def webhook(request: Request):
    raw = await request.body()
    if not verify_webhook_signature(
        raw_body=raw,
        signature_header=request.headers.get("x-replai-signature", ""),
        timestamp_header=request.headers.get("x-replai-timestamp", ""),
        secret=os.environ["WEBHOOK_SECRET"],
    ):
        raise HTTPException(401)
    ...

Reintentos

Replai considera la entrega exitosa con cualquier 2xx. Cualquier otra cosa (timeout, 4xx, 5xx) entra en cola de reintentos con backoff exponencial:

intento 1 → inmediato
intento 2 → +30s
intento 3 → +2min
intento 4 → +10min
intento 5 → +1h
después   → DLQ (dead-letter, sin más reintentos)

Si tu endpoint da 4xx permanente (404, 410), pausamos automáticamente el webhook a las 5 fallas seguidas para no spammearte. Lo reactivas desde el dashboard.

Protección contra replays

verifyWebhookSignature rechaza por defecto deliveries con timestamp fuera del rango de ±5 min (tolerancia configurable). Esto previene replays si alguien intercepta una request vieja.

Webhooks · Replai · WhatsApp con IA en Venezuela