> For the complete documentation index, see [llms.txt](https://docs.caf.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.caf.io/caf-api/caf-api-pt-br/conectar/webhook/request.md).

# Solicitação

## O que o webhook me envia?

O webhook envia um evento via `HTTP` `POST` solicitação com `Content-Type: application/json` com os seguintes parâmetros:

* Um `X-Caf-Signature` cabeçalho usado para verificar se a solicitação veio da Certta

{% content-ref url="/pages/c3bfb0401819a393b215c920baeae12483dc3883" %}
[Assinatura](/caf-api/caf-api-pt-br/conectar/webhook/signature.md)
{% endcontent-ref %}

* O corpo da solicitação é um `JSON` que segue o padrão CloudEvents

{% content-ref url="/pages/d64bfb5898a706ea053a293d72ce5f0317e45ef7" %}
[Eventos](/caf-api/caf-api-pt-br/conectar/webhook/events.md)
{% endcontent-ref %}

## Estrutura da solicitação

Cada solicitação de webhook inclui:

### Cabeçalhos

| Cabeçalho         | Descrição                                                |
| ----------------- | -------------------------------------------------------- |
| `Content-Type`    | Sempre `application/json`                                |
| `User-Agent`      | Identifica-se como `Caf-Webhook/Connect`                 |
| `X-Caf-Signature` | Contém a assinatura HMAC SHA-256 do corpo da solicitação |

### Corpo da solicitação

O corpo da solicitação segue o formato CloudEvents, embora os cabeçalhos HTTP específicos do CloudEvents não estejam incluídos:

```json
{
  "specversion": "1.0",
  "type": "COMMUNICATIONCREATEDEVENT",
  "source": "COMMUNICATION",
  "id": "01JZNK5ZQBNF623MB5KE64GNQB",
  "time": "2025-07-08T18:01:19.622Z",
  "datacontenttype": "application/json",
  "data": {
    "tenantId": "016e8f79-2399-4d35-90f9-c6f91b73189d",
    "channel": "sms",
    "externalId": "external-id",
    "notificationId": "01JZNK51YCZXT55TKF8M366QHJ",
    "system": "onboarding",
    "occurredOn": "2025-07-08T18:00:46.797Z"
  }
}
```

## Exemplos

### Curl

Exemplo de comando curl assumindo `SECRET: "dummysecret"`:

```bash
curl --location 'http://localhost:8080/webhook' \
--header 'X-Caf-Signature: 6f9ed23a7b505a3b6907c5f6eb2ad1b056fbf35a643d365a9a072ed7aabca153' \
--header 'Content-Type: application/json' \
--data '{
  "specversion": "1.0",
  "type": "COMMUNICATIONCREATEDEVENT",
  "source": "COMMUNICATION",
  "id": "01JZNK5ZQBNF623MB5KE64GNQB",
  "time": "2025-07-08T18:01:19.622Z",
  "datacontenttype": "application/json",
  "data": {
    "tenantId": "016e8f79-2399-4d35-90f9-c6f91b73189d",
    "channel": "sms",
    "externalId": "external-id",
    "notificationId": "01JZNK51YCZXT55TKF8M366QHJ",
    "system": "onboarding",
    "occurredOn": "2025-07-08T18:00:46.797Z"
  }
}'
```

{% hint style="warning" %}
É importante validar a assinatura do payload assim que ele chega (como um array de bytes), sem qualquer parsing das informações. Isso garante a integridade da verificação.
{% endhint %}

## O que devo responder ao webhook?

{% hint style="info" %}
Nosso webhook considera respostas com um `2xx` código (de preferência `202 ACCEPTED`) em até 2 segundos como indicação de que a integração recebeu o evento com sucesso e, portanto, nenhuma outra chamada será feita para esse evento. O corpo da resposta é ignorado pelo sistema, exceto para fins de auditoria interna em caso de falhas na entrega.
{% endhint %}

## Casos de erro

A solicitação de webhook tem o objetivo de integrar o evento com sucesso e nada mais do que isso. Com esse objetivo em mente, respostas de erro devem ser usadas apenas para indicar falha na integração do evento (por evento integrado, entende-se que o evento foi recebido com sucesso pelo servidor do webhook).

O mecanismo de entrega do webhook aceita e reconhece erros dentro da série de erros HTTP 5xx, que podem indicar erros no recebimento ou processamento da solicitação pelo servidor. As tentativas de entrega serão feitas apenas para essa classe de erros.

As respostas de erro podem seguir o payload especificado abaixo para detalhar e deixar claro o motivo do erro em nossa auditoria interna. Quaisquer outros campos e/ou formatos serão ignorados.

```json
{
  "error": "mensagem de erro"
}
```

{% hint style="danger" %}
Se todas as tentativas de entrega falharem, o webhook descarta o evento, que não será mais entregue via webhook!

O número máximo de tentativas, o intervalo entre cada tentativa de entrega e o tempo limite ficam a critério da Certta. Atualmente, consideramos como timeout as solicitações que levam mais de 2 segundos para responder e tentamos reenviar os eventos por até 15 minutos.
{% endhint %}

## Tratamento de solicitações de webhook

### Idempotência

{% hint style="info" %}
As solicitações de webhook podem ser entregues mais de uma vez em casos raros. Para lidar com isso, implemente idempotência por meio de:

1. Usando o `id` campo no payload do evento para detectar duplicatas
2. Armazenando os IDs dos eventos processados para evitar processar o mesmo evento duas vezes
3. Tornando sua lógica de tratamento de eventos idempotente (segura para executar várias vezes)
   {% endhint %}

### Exemplo de manipulador de webhook

Aqui está um exemplo simples de manipulador de webhook em Node.js Express:

```javascript
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');

const app = express();
app.use(bodyParser.json());

app.post('/webhook', (req, res) => {
  const sigHeader = req.headers['x-caf-signature'];
  const payload = req.body;
  
  // Verificar a assinatura
  if (!verifySignature(payload, sigHeader, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Assinatura inválida');
  }
  
  // Processar o CloudEvent com base no tipo
  const eventType = payload.type;
  const eventSource = payload.source;
  const eventId = payload.id;
  
  console.log(`Processando CloudEvent: ${eventId} de ${eventSource} do tipo ${eventType}`);
  
  switch (eventType) {
    case 'COMMUNICATIONCREATEDEVENT':
      handleCommunicationCreated(payload.data);
      break;
    case 'TRANSACTIONPROCESSSTARTEDEVENT':
      handleTransactionProcessStarted(payload.data);
      break;
    case 'TRANSACTIONDOCUMENTSCOPYREQUESTEDEVENT':
      handleTransactionDocumentsCopyRequested(payload.data);
      break;
    case 'TRANSACTIONSTATUSUPDATEDEVENT':
      handleTransactionUpdated(payload.data);
      break;
    case 'TRANSACTIONVERIFAIDOCSERROREVENT':
      handleTransactionVerifaiDocsError(payload.data);
      break;
    case 'PROFILEUPDATEDEVENT':
      handleProfileUpdated(payload.data);
      break;
    // Tratar outros tipos de evento...
    default:
      console.log(`Tipo de evento não tratado: ${eventType}`);
  }
  
  // Responder com sucesso
  res.status(200).send('Evento recebido');
});

// Iniciar o servidor
app.listen(3000, () => {
  console.log('Servidor de webhook escutando na porta 3000');
});
```

## Solução de problemas

### Problemas comuns

{% hint style="danger" %}
**401 Unauthorized**

* Seu endpoint retornou o código 401.
* Verifique se você está validando as assinaturas corretamente.

**Timeout**

* Seu endpoint demorou demais para responder.
* Otimize seu código para responder em menos de 2 segundos.

**Conexão recusada**

* A Certta não conseguiu se conectar ao seu endpoint.
* Verifique se seu servidor está em execução e acessível.

**Rejeição de assinatura**

* Falha na validação da assinatura do webhook.
* Verifique se você está usando o segredo correto e validando os bytes brutos do corpo.
  {% endhint %}

### Logs e depuração

Você pode usar os logs do webhook no Trust, a plataforma que gerencia as configurações, para ver o status de entrega dos eventos recentes e quaisquer mensagens de erro. Os logs mantêm um histórico de:

* Tentativas de entrega bem-sucedidas e malsucedidas
* Códigos de resposta HTTP recebidos
* Carimbos de data e hora das entregas
* Erros específicos encontrados durante as entregas


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.caf.io/caf-api/caf-api-pt-br/conectar/webhook/request.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
