> ## Documentation Index
> Fetch the complete documentation index at: https://omniloy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Verificación de firmas HMAC

> Cómo verificar la autenticidad de los webhooks de MarIA usando HMAC-SHA256

Para cada petición de webhook:

1. Lee el **cuerpo RAW** tal cual lo envía el servidor (ojo a middlewares que lo parsean/modifican).
2. Calcula `HMAC_SHA256(secret, rawBody)`.
3. Convierte a **hex lowercase** y compón `sha256=<hex>`.
4. Compara de forma **tiempo‑constante** con el valor de la cabecera `X-Integration-Signature`.

<Warning>
  Rechaza la petición si el skew de tiempo del header `Date` (si se envía) supera 5 minutos.
</Warning>

### Node.js (Express)

```js theme={null}
import crypto from 'node:crypto';

export function verifySignature({ secret, rawBody, header }) {
  const digest = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  const expected = `sha256=${digest}`;
  const provided = String(header || '');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(provided)
  );
}
```

### Python (FastAPI / Starlette)

```py theme={null}
import hmac, hashlib

def verify_signature(secret: str, raw_body: bytes, header: str) -> bool:
    digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    expected = f"sha256={digest}"
    try:
        return hmac.compare_digest(expected, header or "")
    except Exception:
        return False
```

## Reintentos e idempotencia

Si tu endpoint responde `>=500` o no responde a tiempo, MarIA reintentará la entrega.

## Errores frecuentes

<Warning>
  Leer `req.body` ya parseado pierde el RAW. Usa middleware para conservar el buffer antes de cualquier parser.
</Warning>
