# Validando Webhook payload usando x-webhook-signature (Recomendado)

> Toda request do Webhook possui o header `x-webhook-signature` que é a assinatura gerada com a **chave privada da Woovi** e o payload do Webhook.

# Como validar o Webhook Signature? (Recomendado)

## Qual a diferença entre x-webhook-signature e X-OpenPix-Signature (HMAC)?

Existem dois métodos de validação de webhook disponíveis:

| Método | Header | O que valida | Chave utilizada |
|--------|--------|--------------|-----------------|
| **x-webhook-signature** | `x-webhook-signature` | Valida que o webhook veio da **Woovi** (valida o remetente) | Chave pública da Woovi |
| **HMAC** | `X-OpenPix-Signature` | Valida que o webhook veio da **sua configuração específica de webhook** | Secret key do seu webhook |

## Chave Pública da Woovi

:::tip Obtenha a chave pública via API
A chave também está disponível num endpoint aberto:
[GET /api/v1/webhook/public-keys](/api#tag/webhook/GET/api/v1/webhook/public-keys).

Buscar a chave em vez de deixá-la fixa no código é o caminho recomendado: quando a chave
for trocada, sua integração acompanha a troca sozinha. Veja
[Buscando a chave pública da Woovi via API](./webhook-public-keys).
:::

```
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/+NtIkjzevvqD+I3MMv3bLXDt
pvxBjY4BsRrSdca3rtAwMcRYYvxSnd7jagVLpctMiOxQO8ieUCKLSWHpsMAjO/zZ
WMKbqoG8MNpi/u3fp6zz0mcHCOSqYsPUUG19buW8bis5ZZ2IZgBObWSpTvJ0cnj6
HKBAA82Jln+lGwS1MwIDAQAB
-----END PUBLIC KEY-----
```

Para validar o `x-webhook-signature`, você deve usar a **chave pública da Woovi (em Base64)**:

```
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDLytOdElranpldnZxRCtJM01NdjNiTFhEdApwdnhCalk0QnNSclNkY2EzcnRBd01jUllZdnhTbmQ3amFnVkxwY3RNaU94UU84aWVVQ0tMU1dIcHNNQWpPL3paCldNS2Jxb0c4TU5waS91M2ZwNnp6MG1jSENPU3FZc1BVVUcxOWJ1VzhiaXM1WloySVpnQk9iV1NwVHZKMGNuajYKSEtCQUE4MkpsbitsR3dTMU13SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=
```

Esta chave é a mesma para todos os webhooks da Woovi.

Exemplo: `'x-webhook-signature': 'lL2nnXgmLFGgxJ8+jCDguqouU4ucrIxYJcU5SPrJFaNcJajTJHYVldqc/z4YFIjAjtPEALe699WosgPY08W7CLpidvtm06Qwa4YMB0l/DcTS93O91NdSH/adjugEKiOb76Zj/0jB8mqOmWCFYbweOBa17bssuEkd5Lw7Q5L314Y='`

## Exemplo de validação

**PHP**

```php
<?php

function verifyPayload($payload, $signature) {
  $publicKeyBase64 = 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDLytOdElranpldnZxRCtJM01NdjNiTFhEdApwdnhCalk0QnNSclNkY2EzcnRBd01jUllZdnhTbmQ3amFnVkxwY3RNaU94UU84aWVVQ0tMU1dIcHNNQWpPL3paCldNS2Jxb0c4TU5waS91M2ZwNnp6MG1jSENPU3FZc1BVVUcxOWJ1VzhiaXM1WloySVpnQk9iV1NwVHZKMGNuajYKSEtCQUE4MkpsbitsR3dTMU13SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=';

  $publicKey = base64_decode($publicKeyBase64);

  $verify = openssl_verify($payload, base64_decode($signature), $publicKey, "sha256WithRSAEncryption");

  return $verify;
}
// replace to the payload received
$payload = '{ "pixQrCode": null, "charge": { "status": "COMPLETED", "customer": { "name": "Antonio Victor", "taxID": { "taxID": "12345678976", "type": "BR:CPF" }, "email": "antoniocliente@example.com", "correlationID": "4979ceba-2132-4292-bd90-bee7fb2125e4" }, "value": 1000, "comment": "Pagamento OpenPix", "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "correlationID": "417bae21-3d08-4cdb-9c2d-fee63c89e9e4", "paymentLinkID": "34697ed2-3790-4b60-8512-e7465b142d84", "createdAt": "2021-03-12T12:43:54.528Z", "updatedAt": "2021-03-12T12:44:09.360Z", "brCode": "https://api.openpix.com.br/openpix/openpix/testing?transactionID=ea83401ed4834b3ea6f1f283b389af29" }, "pix": { "charge": { "status": "COMPLETED", "customer": { "name": "Antonio Victor", "taxID": { "taxID": "12345678976", "type": "BR:CPF" }, "email": "antoniocliente@example.com", "correlationID": "4979ceba-2132-4292-bd90-bee7fb2125e4" }, "value": 1000, "comment": "Pagamento OpenPix", "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "correlationID": "417bae21-3d08-4cdb-9c2d-fee63c89e9e4", "paymentLinkID": "34697ed2-3790-4b60-8512-e7465b142d84", "createdAt": "2021-03-12T12:43:54.528Z", "updatedAt": "2021-03-12T12:44:09.360Z" }, "customer": { "correlationID": "9134e286-6f71-427a-bf00-241681624586", "email": "email1@example.com", "name": "Loma", "phone": "+5511999999999", "taxID": { "taxID": "47043622050", "type": "BR:CPF" } }, "payer": { "correlationID": "9134e286-6f71-427a-bf00-241681624586", "email": "email1@example.com", "name": "Loma", "phone": "+5511999999999", "taxID": { "taxID": "47043622050", "type": "BR:CPF" } }, "time": "2021-03-12T12:44:09.269Z", "value": 1, "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "infoPagador": "OpenPix testing" }, "company": { "id": "624f46f9e93f9f521c8308d7", "name": "Pizzaria do José", "taxID": "4722767300014" }, "account": { "clientId": "ZOJ64B9B-ZM1W-89MI-4UCI-OP2LVIU6NY75" } }';

// replace to the header signature received into x-webhook-signature
$signature = 'lL2nnXgmLFGgxJ8+jCDguqouU4ucrIxYJcU5SPrJFaNcJajTJHYVldqc/z4YFIjAjtPEALe699WosgPY08W7CLpidvtm06Qwa4YMB0l/DcTS93O91NdSH/adjugEKiOb76Zj/0jB8mqOmWCFYbweOBa17bssuEkd5Lw7Q5L314Y=';

$isValid = verifyPayload($payload, $signature);

if ($isValid) {
  echo "Valid signature\n";
} else {
  echo "Invalid signature\n";
}

```

**JavaScript**

```jsx
import crypto from 'crypto';

type VerifyPayloadType = {
  payload: string;
  signature: string;
};

const algorithm = 'sha256';
const signatureFormat = 'base64';

export const verifyPayload = ({ payload, signature }: VerifyPayloadType) => {
  const publicKeyBase64 =
    'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDLytOdElranpldnZxRCtJM01NdjNiTFhEdApwdnhCalk0QnNSclNkY2EzcnRBd01jUllZdnhTbmQ3amFnVkxwY3RNaU94UU84aWVVQ0tMU1dIcHNNQWpPL3paCldNS2Jxb0c4TU5waS91M2ZwNnp6MG1jSENPU3FZc1BVVUcxOWJ1VzhiaXM1WloySVpnQk9iV1NwVHZKMGNuajYKSEtCQUE4MkpsbitsR3dTMU13SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=';

  const publicKey = Buffer.from(publicKeyBase64, 'base64').toString('ascii');

  const verify = crypto.createVerify(algorithm);

  verify.write(Buffer.from(payload));
  verify.end();

  const isValid = verify.verify(publicKey, signature, signatureFormat);

  return isValid;
};

// replace to the payload received into body
const payload =
  '{ "pixQrCode": null, "charge": { "status": "COMPLETED", "customer": { "name": "Antonio Victor", "taxID": { "taxID": "12345678976", "type": "BR:CPF" }, "email": "antoniocliente@example.com", "correlationID": "4979ceba-2132-4292-bd90-bee7fb2125e4" }, "value": 1000, "comment": "Pagamento OpenPix", "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "correlationID": "417bae21-3d08-4cdb-9c2d-fee63c89e9e4", "paymentLinkID": "34697ed2-3790-4b60-8512-e7465b142d84", "createdAt": "2021-03-12T12:43:54.528Z", "updatedAt": "2021-03-12T12:44:09.360Z", "brCode": "https://api.openpix.com.br/openpix/openpix/testing?transactionID=ea83401ed4834b3ea6f1f283b389af29" }, "pix": { "charge": { "status": "COMPLETED", "customer": { "name": "Antonio Victor", "taxID": { "taxID": "12345678976", "type": "BR:CPF" }, "email": "antoniocliente@example.com", "correlationID": "4979ceba-2132-4292-bd90-bee7fb2125e4" }, "value": 1000, "comment": "Pagamento OpenPix", "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "correlationID": "417bae21-3d08-4cdb-9c2d-fee63c89e9e4", "paymentLinkID": "34697ed2-3790-4b60-8512-e7465b142d84", "createdAt": "2021-03-12T12:43:54.528Z", "updatedAt": "2021-03-12T12:44:09.360Z" }, "customer": { "correlationID": "9134e286-6f71-427a-bf00-241681624586", "email": "email1@example.com", "name": "Loma", "phone": "+5511999999999", "taxID": { "taxID": "47043622050", "type": "BR:CPF" } }, "payer": { "correlationID": "9134e286-6f71-427a-bf00-241681624586", "email": "email1@example.com", "name": "Loma", "phone": "+5511999999999", "taxID": { "taxID": "47043622050", "type": "BR:CPF" } }, "time": "2021-03-12T12:44:09.269Z", "value": 1, "transactionID": "ea83401ed4834b3ea6f1f283b389af29", "infoPagador": "OpenPix testing" }, "company": { "id": "624f46f9e93f9f521c8308d7", "name": "Pizzaria do José", "taxID": "4722767300014" }, "account": { "clientId": "ZOJ64B9B-ZM1W-89MI-4UCI-OP2LVIU6NY75" } }';

// replace to the payload received into x-webhook-signature header
const signature =
  'lL2nnXgmLFGgxJ8+jCDguqouU4ucrIxYJcU5SPrJFaNcJajTJHYVldqc/z4YFIjAjtPEALe699WosgPY08W7CLpidvtm06Qwa4YMB0l/DcTS93O91NdSH/adjugEKiOb76Zj/0jB8mqOmWCFYbweOBa17bssuEkd5Lw7Q5L314Y=';

const isValid = verifyPayload({ payload, signature });

if (isValid) {
  console.log('Valid signature');
} else {
  console.log('Invalid signature');
}
```
