Skip to main content

Webhooks (notificaciones push)

Cuando el estado de una transacción cambia (pago procesado, rechazo), CUCU envía una notificación push al webhook_url registrado del comercio.

Payload del evento

{
  "type": "qr.status_changed",
  "data": {
    "transactionId": "QR2026061500001",
    "status": "PAID",
    "amount": "150.00",
    "currency": "BOB",
    "commerceCode": "mi-comercio",
    "externalReference": "ORD-2026-00871",
    "paidAt": "2026-06-15T14:12:33Z",
    "payerDocument": "12345678",
    "payerName": "Juan Pérez"
  }
}

Seguridad del webhook

CUCU firma cada notificación con HMAC-SHA256 usando el webhook_secret entregado en el onboarding. El comercio debe verificar la firma antes de procesar el evento:
X-CUCU-Signature: sha256=<hex_digest>
Verificación en Python:
import hmac
import hashlib

def verify_webhook(payload_bytes: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload_bytes,
        hashlib.sha256
    ).hexdigest()
    received = signature_header.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)
Verificación en Node.js:
const crypto = require("crypto");

function verifyWebhook(payloadBuffer, signatureHeader, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payloadBuffer)
    .digest("hex");
  const received = signatureHeader.replace("sha256=", "");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(received)
  );
}

Política de reintentos

Si el endpoint del comercio no responde con 2xx en 10 segundos, CUCU reintenta con backoff exponencial: 30 s → 2 min → 10 min → 1 h → 6 h. Después de 5 intentos fallidos el evento queda en Dead Letter Queue (DLQ) y el equipo de CUCU es notificado.