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

# Webhooks | Validar solicitações

> Uma visão geral das solicitações de validação com origem da HubSpot para uma integração. 

Para garantir que as solicitações que sua integração esteja recebendo da HubSpot venham realmente da HubSpot, vários cabeçalhos são preenchidos na solicitação. Você pode usar esses cabeçalhos, juntamente com os campos da solicitação recebida, para verificar a assinatura da solicitação.

O método usado para verificar a assinatura depende da versão da assinatura.

* Para validar uma solicitação usando a versão mais recente da assinatura do HubSpot, use o cabeçalho `X-HubSpot-Signature-V3` e siga as instruções[ associadas para validar a versão v3 da assinatura](/apps/legacy-apps/authentication/validating-requests#validate-the-v3-request-signature).
* Para compatibilidade com versões anteriores, as solicitações do HubSpot também incluem versões mais antigas da assinatura. Para validar uma versão mais antiga da assinatura, verifique o cabeçalho`X-HubSpot-Signature-Version` e siga as instruções associadas abaixo com base em se a versão é `v1` ou `v2`.

Nas instruções abaixo, saiba como derivar um valor de hash do segredo do cliente do seu aplicativo e dos campos de uma solicitação recebida. Depois de calcular o valor do hash, você o comparará à assinatura. Se os dois forem iguais, a solicitação passará na validação. Caso contrário, a solicitação pode ter sido alterada em trânsito ou alguém pode estar falsificando solicitações para seu ponto de extremidade.

## Validar solicitações usando a assinatura de solicitação v1

Se seu aplicativo estiver inscrito em [eventos de objetos do CRM por meio da API do webhooks](/api-reference/webhooks-webhooks-v3/guide), as solicitações do HubSpot serão enviadas com o cabeçalho `X-HubSpot-Signature-Version` definido como `v1`. O cabeçalho `X-HubSpot-Signature` será um hash SHA-256 gerado usando o segredo do cliente do seu aplicativo combinado com detalhes da solicitação.

Para verificar a versão da assinatura, siga as seguintes etapas:

* Crie uma string que concatene o seguinte: `Client secret` + `request body` (se presente).
* Crie um hash SHA-256 da string resultante.
* Compare o valor de hash com o valor do cabeçalho `X-HubSpot-Signature`:
  * Se forem iguais, essa solicitação passou na validação.
  * Se esses valores forem diferentes, essa solicitação pode ter sido alterada em trânsito ou alguém pode ter falsificado solicitações no seu ponto de extremidade.

**Exemplo de uma solicitação com um corpo:**

```json theme={null}
//Client secret : yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
// Request body: [
{"eventId":1,"subscriptionId":12345,"
portalId":62515",
occurredAt":1564113600000",
subscriptionType":"contact.creation",
"attemptNumber":0,
"objectId":123,
"changeSource":"CRM",
"changeFlag":"NEW",
"appId":54321}
]
```

## Exemplos de assinatura de solicitação v1:

### Exemplo em Python

```py theme={null}
NOTE: This is only an example for generating the expected hash.
You will need to compare this expected hash with the actual hash in the
X-HubSpot-Signature header.

>>> import hashlib

>>> client_secret = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'
>>> request_body = '[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
>>> source_string = client_secret + request_body
>>> source_string
'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
>>> hashlib.sha256(source_string).hexdigest()
'232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de'
```

### Exemplo em Ruby

```ruby theme={null}
NOTE: This is only an example for generating the expected hash.
You will need to compare this expected hash with the actual hash in the
X-HubSpot-Signature header.

irb(main):003:0> require 'digest'
=> true
irb(main):004:0> client_secret = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'
=> "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
irb(main):005:0> request_body = '[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
=> "[{\"eventId\":1,\"subscriptionId\":12345,\"portalId\":62515,\"occurredAt\":1564113600000,\"subscriptionType\":\"contact.creation\",\"attemptNumber\":0,\"objectId\":123,\"changeSource\":\"CRM\",\"changeFlag\":\"NEW\",\"appId\":54321}]"
irb(main):006:0> source_string = client_secret + request_body
=> "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy[{\"eventId\":1,\"subscriptionId\":12345,\"portalId\":62515,\"occurredAt\":1564113600000,\"subscriptionType\":\"contact.creation\",\"attemptNumber\":0,\"objectId\":123,\"changeSource\":\"CRM\",\"changeFlag\":\"NEW\",\"appId\":54321}]"
irb(main):007:0> Digest::SHA256.hexdigest source_string
=> "232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de"
```

### Exemplo em Node.js

```js theme={null}
NOTE: This is only an example for generating the expected hash.
You will need to compare this expected hash with the actual hash in the
X-HubSpot-Signature header.

> const crypto = require('crypto')
undefined
> client_secret = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'
'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'
> request_body = '[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
'[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
> source_string = client_secret + request_body
'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
> hash = crypto.createHash('sha256').update(source_string).digest('hex')
'232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de'
```

### Exemplo em Java

```java theme={null}
// NOTE: This is only an example for generating the expected hash.
// You will need to compare this expected hash with the actual hash in the
// X-HubSpot-Signature header.

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;

public class HubSpotSignatureValidator {

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        String clientSecret = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
        String requestBody = "[{\"eventId\":1,\"subscriptionId\":12345,\"portalId\":62515,\"occurredAt\":1564113600000,\"subscriptionType\":\"contact.creation\",\"attemptNumber\":0,\"objectId\":123,\"changeSource\":\"CRM\",\"changeFlag\":\"NEW\",\"appId\":54321}]";

        String sourceString = clientSecret + requestBody;
        System.out.println("Source string: " + sourceString);

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(sourceString.getBytes("UTF-8"));

        // Convert to hex string (Java 17+)
        String hexString = java.util.HexFormat.of().formatHex(hash);

        System.out.println("Hash: " + hexString);
        // Output: 232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de
    }
}
```

O hash resultante seria: `232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de`

## Validar solicitações usando a assinatura de solicitação v2

Se seu aplicativo gerencia dados de uma [ação de webhook em um fluxo de trabalho](https://knowledge.hubspot.com/pt/workflows/how-do-i-use-webhooks-with-hubspot-workflows) ou se você estiver retornando dados para um [cartão de CRM personalizado](/api-reference/crm-public-app-crm-cards-v3/guide), a solicitação do HubSpot será enviada com o cabeçalho `X-HubSpot-Signature-Version` definido como `v2`. O cabeçalho `X-HubSpot-Signature` será um hash SHA-256 gerado usando o segredo do cliente do seu aplicativo combinado com detalhes da solicitação.

Para verificar essa assinatura, execute as seguintes etapas:

* Crie uma string que concatene o seguinte: `Client secret` + `http method` + `URI` + `request body` (se presente).
* Crie um hash SHA-256 da string resultante.
* Compare o valor do hash à assinatura.
  * Se forem iguais, essa solicitação passou na validação.
  * Se esses valores forem diferentes, essa solicitação pode ter sido alterada em trânsito ou alguém pode ter falsificado solicitações no seu ponto de extremidade.

**Observações:**

* A URI usada para construir a string de origem deve corresponder exatamente à solicitação original, incluindo o protocolo. Se você tiver problemas para validar a assinatura, verifique se todos os parâmetros de consulta estão na mesma ordem em que foram listados na solicitação original.
* A string de origem deve ser de codificado em UTF-8 antes de calcular o hash SHA-256.

### Exemplo de uma solicitação GET

Para uma solicitação `GET`, você precisaria do segredo do cliente do seu aplicativo e de campos específicos dos metadados da sua solicitação. Esses campos estão listados abaixo com valores de espaço reservado incluídos:

* **Segredo do cliente:** `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy`
* **Método HTTP:** `GET`
* **URI:** `https://www.example.com/webhook_uri`
* **Corpo da solicitação:`""`**

A string concatenada resultante seria: `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyyGEThttps://www.example.com/webhook_uri`

Depois de calcular um hash SHA-256 da string concatenada acima, a assinatura resultante que você espera corresponder à do cabeçalho seria: `eee2dddcc73c94d699f5e395f4b9d454a069a6855fbfa152e91e88823087200e`

### Exemplo de uma solicitação POST

Para uma solicitação `POST`, você precisaria do segredo do cliente do seu aplicativo, campos específicos dos metadados da sua solicitação e uma representação de string do corpo da solicitação (por exemplo, usando `JSON.stringify(request.body)` para um serviço Node.js). Esses campos estão listados abaixo com valores de espaço reservado incluídos:

* **Segredo do cliente:** `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy`
* **Método HTTP:** `POST`
* **URI:** `https://www.example.com/webhook_uri`
* **Corpo da solicitação:**`{"example_field":"example_value"}`

A string concatenada resultante seria: `yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyyPOSThttps://www.example.com/webhook_uri{"example_field":"example_value"}`

Depois de calcular um hash SHA-256 da string concatenada acima, a assinatura resultante que você espera corresponder à do cabeçalho seria:`9569219f8ba981ffa6f6f16aa0f48637d35d728c7e4d93d0d52efaa512af7900`

Após fazer um \[SHA] da assinatura, você pode então comparar a assinatura esperada resultante com aquela fornecida no cabeçalho x-hubspot-signature da solicitação:

Os trechos de código abaixo detalham como você pode incorporar a validação do pedido `v2` para um pedido `GET` se você estivesse executando um servidor Express para lidar com solicitações de entrada. Lembre-se de que o bloco de código abaixo é um exemplo e omite certas dependências que talvez sejam necessárias para executar um serviço Express completo. Confirme se você está executando as bibliotecas estáveis e seguras mais recentes ao implementar a validação de solicitação para seu serviço específico.

## Exemplos de assinatura de solicitação v2:

### Exemplo em Node.js

```js theme={null}
// Introduce any dependencies. Only several dependencies related to this example are included below:
const express = require("express");
const bodyParser = require("body-parser");
const crypto = require("crypto");
const app = express();

// Add any custom handling or setup code for your Node.js service here.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// Example Node.js request validation code.
app.get("/example-service", (request, response, next) => {
  const { url, method, headers, hostname } = request;

  const requestSignature = headers["x-hubspot-signature"];

  // Compute expected signature
  const uri = `https://${hostname}${url}`;
  const encodedString = Buffer.from(`${process.env.CLIENT_SECRET}${method}${uri}`, "ascii").toString("utf-8");
  const expectedSignature = crypto.createHash("sha256").update(encodedString).digest("hex");

  console.log("Expected signature: %s", requestSignature);
  console.log("Request signature: %s", expectedSignature);

  // Add your custom handling to compare request signature to expected signature
  if (requestSignature !== expectedSignature) {
    console.log("Request of signature does NOT match!");
    response.status(400).send("Bad request");
  } else {
    console.log("Request of signature matches!");
    response.status(200).send();
  }
});
```

### Exemplo em Java

```java theme={null}
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;

public class HubSpotV2SignatureValidator {

    public static boolean validateV2Signature(String clientSecret, String method,
                                                String uri,
                                                String receivedSignature) {
        try {
          // Create concatenated string: client_secret + method + uri + body
          String sourceString = clientSecret + method + uri;
          System.out.println("Source string: " + sourceString);

          // Create SHA-256 hash
          MessageDigest digest = MessageDigest.getInstance("SHA-256");
          byte[] hash = digest.digest(sourceString.getBytes(StandardCharsets.UTF_8));

          // Convert to hex string (Java 17+)
          String expectedSignature = java.util.HexFormat.of().formatHex(hash);

          // Compare signatures using constant-time comparison
          return MessageDigest.isEqual(expectedSignature.getBytes(), receivedSignature.getBytes());

        } catch (NoSuchAlgorithmException e) {
          throw new RuntimeException("SHA-256 algorithm not available", e);
        }
      }

      // Example usage
      public static void main(String[] args) {
        String clientSecret = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
        String method = "GET";
        String uri = "https://www.example.com/webhook_uri";

        // Expected signature: 9569219f8ba981ffa6f6f16aa0f48637d35d728c7e4d93d0d52efaa512af7900
        String expectedSignature = "9569219f8ba981ffa6f6f16aa0f48637d35d728c7e4d93d0d52efaa512af7900";

        boolean isValid = validateV2Signature(clientSecret, method, uri, expectedSignature);
        if (isValid) {
          System.out.println("Signature is valid!");
        }
        // Proceed with any request processing as needed.
       else {
        System.out.println("Signature is invalid!");
        // Add any rejection logic here. e.g, throw 400
        }
      }
}
```

## Validar assinaturas de solicitação v3

O cabeçalho `X-HubSpot-Signature-v3` será um hash HMAC SHA-256 gerado usando o segredo do cliente do seu aplicativo combinado com detalhes da solicitação. Também conterá o cabeçalho `X-HubSpot-Request-Timestamp`.

Ao validar uma solicitação usando o cabeçalho X-HubSpot-Signature-v3, você precisará

* Rejeitar a solicitação se o registro de data/hora tiver mais de 5 minutos.
* Na URI da solicitação, decodificar todos os caracteres codificados por URL listados na tabela abaixo. Você não precisa decodificar o ponto de interrogação que indica o início da string de consulta.

| **Valor codificado** | **Valor decodificado** |
| -------------------- | ---------------------- |
| `%3A`                | `:`                    |
| `%2F`                | `/`                    |
| `%3F`                | `?`                    |
| `%40`                | `@`                    |
| `%21`                | `!`                    |
| `%24`                | `$`                    |
| `%27`                | `'`                    |
| `%28`                | `(`                    |
| `%29`                | `)`                    |
| `%2A`                | `*`                    |
| `%2C`                | `,`                    |
| `%3B`                | `;`                    |

* Crie uma string com codificação utf-8 que concatene o seguinte: `requestMethod` + `requestUri` + `requestBody` + data/hora. O registro de data e hora é fornecido pelo cabeçalho `X-HubSpot-Request-Timestamp`.
* Crie um hash HMAC SHA-256 da string resultante usando o segredo do aplicativo como o segredo da função HMAC SHA-256.
* A Base64 codifica o resultado da função do HMAC.
* Compare o valor do hash à assinatura. Se forem iguais, a origem da solicitação foi confirmada como sendo da HubSpot. É recomendado usar uma comparação de string de tempo constante para proteger contra ataques de sincronização.

Os trechos de código na seção abaixo detalham como você pode incorporar a validação de solicitação v3 para um pedido `POST` se você estivesse executando um serviço de backend para lidar com solicitações recebidas. Tenha em mente que os blocos de código abaixo omitem certas dependências que você pode precisar para executar um serviço de backend completo. Confirme se você está executando as bibliotecas estáveis e seguras mais recentes ao implementar a validação de solicitação para seu serviço específico.

## Exemplos de assinatura de solicitação v3

### Exemplo em Node.js

```js theme={null}
// Introduce any dependencies. Only several dependencies related to this example are included below:
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const crypto = require("crypto");
const app = express();
const port = process.env.PORT || 4000;

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.post("/webhook-test", (request, response) => {
  response.status(200).send("Received webhook subscription trigger");

  const { url, method, body, headers, hostname } = request;

  // Parse headers needed to validate signature
  const signatureHeader = headers["x-hubspot-signature-v3"];
  const timestampHeader = headers["x-hubspot-request-timestamp"];

  // Validate timestamp
  const MAX_ALLOWED_TIMESTAMP = 300000; // 5 minutes in milliseconds
  const currentTime = Date.now();
  if (currentTime - timestampHeader > MAX_ALLOWED_TIMESTAMP) {
    console.log("Timestamp is invalid, reject request");
    // Add any rejection logic here
  }

  // Concatenate request method, URI, body, and header timestamp
  const uri = `https://${hostname}${url}`;
  const rawString = `${method}${uri}${JSON.stringify(body)}${timestampHeader}`;

  // Create HMAC SHA-256 hash from resulting string above, then base64-encode it
  const hashedString = crypto.createHmac("sha256", process.env.CLIENT_SECRET).update(rawString).digest("base64");

  // Validate signature: compare computed signature vs. signature in header
  if (crypto.timingSafeEqual(Buffer.from(hashedString), Buffer.from(signatureHeader))) {
    console.log("Signature matches! Request is valid.");
    // Proceed with any request processing as needed.
  } else {
    console.log("Signature does not match: request is invalid");
    // Add any rejection logic here.
  }
});
```

### Exemplo em Java

```java theme={null}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class HubSpotV3SignatureValidator {

    // 5 minutes in milliseconds
    private static final long MAX_ALLOWED_TIMESTAMP = 300000;

      public static boolean validateV3Signature(String clientSecret, String method,
                                                String uri, String requestBody,
                                                long timestamp, String receivedSignature) {
        try {
          // Validate timestamp (reject if older than 5 minutes)
          long currentTime = System.currentTimeMillis();
          if (currentTime - timestamp > MAX_ALLOWED_TIMESTAMP) {
            System.out.println("Timestamp is invalid, rejecting request");
            return false;
          }

          // Create concatenated string: method + uri + body + timestamp
          String rawString = method + uri + requestBody + timestamp;
          System.out.println("Raw string: " + rawString);

          // Create HMAC SHA-256 hash
          Mac hmacSha256 = Mac.getInstance("HmacSHA256");
          SecretKeySpec secretKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
          hmacSha256.init(secretKey);

          byte[] hash = hmacSha256.doFinal(rawString.getBytes(StandardCharsets.UTF_8));

          // Base64 encode the result
          String expectedSignature = Base64.getEncoder().encodeToString(hash);

          // Compare signatures using constant-time comparison
          return MessageDigest.isEqual(expectedSignature.getBytes(), receivedSignature.getBytes());

        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
          throw new RuntimeException("Error creating HMAC SHA-256 hash", e);
        }
      }

      // Example usage
      public static void main(String[] args) {
        String clientSecret = "cfc68c0b-4b4e-4ef8-b764-95350e4ea479";
        String method = "POST";
        String uri = "https://webhook.site/335453f5-94b3-49d9-b684-a55354d4b8df";
        String requestBody = "[{\"eventId\":531833541,\"subscriptionId\":3923621,\"portalId\":48807704,\"appId\":16111050,\"occurredAt\":1752613920733,\"subscriptionType\":\"contact.creation\",\"attemptNumber\":0,\"objectId\":138017612137,\"changeFlag\":\"CREATED\",\"changeSource\":\"CRM_UI\",\"sourceId\":\"userId:76023669\"}]";
        long timestamp = 1752613922216L; // Example timestamp in milliseconds

        // This would typically come from the X-HubSpot-Signature-v3 header
        String signatureFromHeader = "gbj1XPRvUt0noT7i7fXfTzOD4sLzQmf0VT28ZYq0EYg=";

        boolean isValid = validateV3Signature(clientSecret, method, uri, requestBody, timestamp, signatureFromHeader);
        if(isValid) {
          System.out.println("Signature is valid! Proceed with request processing.");
        }
        // Proceed with any request processing as needed.
       else {
        System.out.println("Signature is invalid! Reject the request.");
        // Add any rejection logic here, e.g., throw 400 Bad Request
        }
      }
}
```
