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

# Assinatura HMAC-SHA256

> Geração e verificação de X-Jelou-Signature no Canal Personalizado

O header `X-Jelou-Signature` com formato `sha256=<HMAC_HEX>` é usado nas **duas direções**. A `signingKey` é obrigatória ao ativar o canal.

* **Entrada (seu app → Jelou):** você deve gerar a assinatura ao chamar `POST /v1/custom-channel/:botId` e `POST /v1/custom-channel/:botId/status`.
* **Saída (Jelou → seu webhook):** você deve verificar a assinatura de cada entrega no seu `webhookUrl` antes de processar o payload.

A assinatura é **independente** de `credentials.auth` (api\_key / bearer / basic).

***

## Gerar assinatura em requisições de entrada

Assine o **raw body** exato que você envia (os mesmos bytes do body HTTP), não um objeto re-serializado diferente. Aplica-se a enviar interação e a consultar status.

```javascript theme={null}
const crypto = require("crypto");

function signBody(rawBody, signingKey) {
  const digest = crypto
    .createHmac("sha256", signingKey)
    .update(rawBody)
    .digest("hex");

  return `sha256=${digest}`;
}

const body = JSON.stringify({
  referenceId: "user-123",
  message: { type: "TEXT", text: "Olá" },
});

const signature = signBody(body, process.env.SIGNING_KEY);
// Header: X-Jelou-Signature: sha256=...
```

<Warning>
  Use a mesma string/buffer enviada na requisição. Re-serializar o JSON com ordem de chaves ou espaços diferentes quebra a verificação.
</Warning>

***

## Verificar assinatura dos eventos recebidos no seu webhook

A Jelou assina o JSON stringificado do payload de saída (`JSON.stringify` do envelope completo).

```javascript theme={null}
const crypto = require("crypto");

function verifySignature(rawBody, signatureHeader, signingKey) {
  const expected = `sha256=${crypto
    .createHmac("sha256", signingKey)
    .update(rawBody)
    .digest("hex")}`;

  if (!signatureHeader) {
    return false;
  }

  const provided = Buffer.from(signatureHeader, "utf8");
  const expectedBuf = Buffer.from(expected, "utf8");

  if (provided.length !== expectedBuf.length) {
    return false;
  }

  return crypto.timingSafeEqual(provided, expectedBuf);
}
```

Leia o body como string raw (antes de fazer o parse) e compare com o header `X-Jelou-Signature`.
