--- title: 8.1. Visão Geral url: https://docs.vehub.com.br/Emiss%C3%A3o%20de%20Ativos/API/Cr%C3%A9dito/8.%20Notifica%C3%A7%C3%B5es%20-%20WebHook/8.1.%20Vis%C3%A3o%20Geral/ --- # 8.1. Visão Geral !!! warning "Especificação — em construção" Os serviços descritos nesta área ainda não estão disponíveis. ## 🧾 Descrição O VeTrust envia notificações via **WebHook** para informar sobre **mudanças de estado** nas operações de crédito: conclusão de simulação, resultado da análise, registro da proposta, formalização e movimentação de parcelas. Assinar os eventos é o que tira a sua integração do *polling*. As operações assíncronas descritas em [1.3. Operações Assíncronas](../1.%20Início/1.3.%20Operações%20Assíncronas.md) todas concluem por webhook. A entrega é tentada com **retry exponencial com jitter** em caso de falhas transitórias, e cada disparo carrega uma **chave de idempotência** que permite deduplicar entregas repetidas com segurança. --- ## 🔔 Tipos de Eventos | Slug (`tipoEvento`) | Página | Quando é disparado | |---|---|---| | `credito.simulacao.concluida` | [8.2](8.2.%20Eventos%20de%20Simulação.md) | O cálculo da simulação da proposta é concluído | | `credito.simulacao.falhou` | [8.2](8.2.%20Eventos%20de%20Simulação.md) | O cálculo é recusado pela bancarizadora | | `credito.analise.concluida` | [8.3](8.3.%20Eventos%20de%20Análise%20de%20Crédito.md) | O motor de crédito devolve o resultado, aprovado ou não | | `credito.proposta.enviada` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | A proposta entra em envio à bancarizadora | | `credito.proposta.registrada` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | A proposta é registrada e a CCB é numerada | | `credito.proposta.falhou` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | O registro é recusado | | `credito.assinatura.aguardando` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | A formalização começa e os assinantes são notificados | | `credito.contrato.formalizado` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | A formalização se conclui e o contrato fica ativo | | `credito.contrato.cancelado` | [8.4](8.4.%20Eventos%20de%20Proposta%20e%20Formalização.md) | A operação é cancelada | | `credito.parcela.cobranca_registrada` | [8.5](8.5.%20Eventos%20de%20Parcela.md) | Uma cobrança é emitida para a parcela | | `credito.parcela.liquidada` | [8.5](8.5.%20Eventos%20de%20Parcela.md) | Uma parcela é baixada | | `credito.contrato.liquidado` | [8.5](8.5.%20Eventos%20de%20Parcela.md) | A última parcela em aberto é baixada | > Uma mesma **configuração de webhook** pode estar inscrita em **um ou mais** tipos de evento. Todos > os eventos inscritos são entregues na mesma URL — use o campo `tipoEvento` (ou o header > `X-Event-Type`) para rotear o processamento. --- ## 📦 Envelope Padrão Todos os eventos compartilham o mesmo envelope. O conteúdo específico fica em `dados`. ```json { "idWebhook": "019e0892-8d99-778c-9fa5-47bd07cd9ffb", "tipoEvento": "credito.analise.concluida", "dataHora": "2026-08-20T13:22:40.512Z", "grupoEconomico": "MeuGrupo", "dados": { }, "etiquetas": null } ``` ### 🧾 Detalhamento dos Campos do Envelope | Campo | Tipo | Descrição | |-------|------|-----------| | `idWebhook` | string (GUID) | Identificador único do disparo. **Use para deduplicação.** Também enviado no header `X-Idempotency-Key` | | `tipoEvento` | string | Slug do evento. Sempre ASCII. Também no header `X-Event-Type` | | `dataHora` | string (ISO 8601, UTC) | Momento em que o evento foi gerado | | `grupoEconomico` | string | Grupo econômico que originou o evento | | `dados` | object | Payload específico do tipo de evento | | `etiquetas` | object / null | Pares chave/valor para extensão. Em disparos reais vem `null`; em disparos de **teste** vem preenchido | --- ## 🔐 Autenticação O VeTrust envia a requisição já autenticada conforme o **modo de autenticação** configurado: | Tipo | Valor | Headers/Body adicionados | Observações | |---|---|---|---| | `SemAutenticacao` | 1 | nenhum | Use apenas em endpoints protegidos por outra camada | | `ApiKey` | 2 | `X-Api-Key: ` | Chave fixa, simples e amplamente compatível | | `Basic` | 3 | `Authorization: Basic base64(clientId:clientSecret)` | Padrão HTTP Basic | | `BearerTokenFixo` | 4 | `Authorization: Bearer ` | Token estático configurado uma vez | | `OAuth2` | 5 | `Authorization: Bearer ` obtido via `client_credentials` | O VeTrust busca o token antes de enviar | | `ClientIdClientSecret` | 6 | `X-Client-Id` e `X-Client-Secret` | Headers separados | > **A URL de envio precisa ser HTTPS.** Configurações com `http://` são recusadas. --- ## ✍️ Assinatura HMAC (opcional, recomendada) Quando o webhook é configurado com um **segredo HMAC**, o VeTrust assina cada disparo com **HMAC-SHA256** sobre o **corpo bruto da requisição** e envia o hash no header: ```http X-Webhook-Signature: sha256= ``` ### Validação no consumidor (Node.js) ```js const crypto = require('crypto'); function validarAssinatura(corpoBruto, headerAssinatura, segredo) { const esperado = crypto .createHmac('sha256', segredo) .update(corpoBruto, 'utf8') .digest('hex'); const recebido = (headerAssinatura || '').replace(/^sha256=/, ''); return crypto.timingSafeEqual( Buffer.from(esperado, 'hex'), Buffer.from(recebido, 'hex') ); } ``` ### Validação no consumidor (C#) ```csharp using System.Security.Cryptography; using System.Text; bool ValidarAssinatura(string corpoBruto, string headerAssinatura, string segredo) { using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(segredo)); var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(corpoBruto)); var esperado = Convert.ToHexString(hash).ToLowerInvariant(); var recebido = (headerAssinatura ?? string.Empty).Replace("sha256=", string.Empty); return CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(esperado), Encoding.UTF8.GetBytes(recebido)); } ``` > **Importante:** valide a assinatura sobre o **corpo bruto recebido**, antes de qualquer parsing > JSON. Frameworks que reformatam JSON antes da validação causam mismatch. --- ## 📨 Headers Padrão | Header | Exemplo | Descrição | |---|---|---| | `Content-Type` | `application/json; charset=utf-8` | Sempre JSON UTF-8 | | `X-Idempotency-Key` | `019e0892-8d99-778c-9fa5-47bd07cd9ffb` | Mesmo valor de `idWebhook` no envelope | | `X-Event-Type` | `credito.analise.concluida` | Slug do evento, útil para roteamento | | `X-Webhook-Signature` | `sha256=fa1be9...` | Presente apenas quando há segredo HMAC configurado | | `Authorization` ou afins | depende do modo | Ver tabela de autenticação | --- ## 🔁 Retry e Entrega A entrega é considerada bem-sucedida quando o consumidor responde com **status HTTP 2xx**. Em caso de falha transitória (**5xx**, **408**, **429**, timeout, DNS, conexão recusada), há **retry exponencial com jitter**. Os demais erros **4xx não são retentados**. | Tentativa | Delay aproximado | |-----------|------------------| | 1 | imediato | | 2 | ~1s + jitter | | 3 | ~2s + jitter | | 4 | ~4s + jitter | | 5 | ~8s + jitter | Após **5 tentativas** sem sucesso, o disparo é registrado como falho e **não é mais retentado automaticamente**. > **Responda 2xx assim que receber**, idealmente em menos de 5 segundos, e processe de forma > assíncrona. Processamento pesado dentro do handler leva a timeout e retry desnecessário. --- ## 🪞 Idempotência Como retries podem entregar a mesma notificação mais de uma vez, o consumidor **deve deduplicar** usando o `idWebhook` (ou o header `X-Idempotency-Key`). Padrão recomendado: 1. Ao receber, persista `idWebhook` em uma tabela com *unique constraint*. 2. Se o `INSERT` falhar com violação de unicidade, retorne **200 OK** sem reprocessar. 3. Senão, processe normalmente. --- ## ⏱️ A ordem das entregas não é garantida Dois eventos da mesma proposta podem chegar fora de ordem. Não construa a sua máquina de estados a partir da sequência de recebimento. Padrão recomendado: ao receber um evento, **consulte o recurso** (`GET /credito/propostas/{id}` ou `GET /credito/contratos/{id}`) e reconcilie com o estado atual. Use o evento como **gatilho**, não como fonte da verdade. --- ## 🛠️ Configuração ### 🔗 Endpoints | Método | URL | |--------|-----| | ![GET](https://img.shields.io/badge/GET-green) | `/webhooks` | | ![POST](https://img.shields.io/badge/POST-blue) | `/webhooks` | | ![GET](https://img.shields.io/badge/GET-green) | `/webhooks/{idWebhook}` | | ![PUT](https://img.shields.io/badge/PUT-orange) | `/webhooks/{idWebhook}` | | ![DELETE](https://img.shields.io/badge/DELETE-red) | `/webhooks/{idWebhook}` | | ![POST](https://img.shields.io/badge/POST-blue) | `/webhooks/{idWebhook}/teste` | | ![GET](https://img.shields.io/badge/GET-green) | `/webhooks/{idWebhook}/disparos` | ### 📤 Criar configuração ```json { "url": "https://meusistema.com.br/webhooks/vetrust", "tiposEvento": [ "credito.analise.concluida", "credito.proposta.registrada", "credito.contrato.formalizado", "credito.parcela.liquidada" ], "tipoAutenticacao": 2, "apiKey": "sua-chave-secreta", "segredoHmac": "minimo-16-caracteres", "ativo": true } ``` | Campo | Tipo | Obrigatório | Descrição | |-------|------|-------------|-----------| | url | string | Sim | URL de destino. **HTTPS obrigatório** | | tiposEvento | array | Sim | Um ou mais slugs dos eventos desejados | | tipoAutenticacao | integer | Sim | Ver tabela de autenticação | | apiKey / clientId / clientSecret / token / urlAutenticacao | string | Condicional | Conforme o modo escolhido | | segredoHmac | string | Não | Mínimo 16 caracteres. Recomendado | | ativo | boolean | Não | `true` por padrão | ### 🧪 Disparo de teste ```bash curl -X POST "https://api.vehub.com.br/webhooks/019e0892-8d99-778c-9fa5-47bd07cd9ffb/teste" \ -H "Authorization: Bearer {seu_token}" \ -H "GrupoEconomico: {seu_grupo_economico}" ``` Envia um payload **realístico** do tipo de evento configurado, com identificadores fictícios e a etiqueta `isTeste = "true"` no envelope. É *single-shot*, sem retry. Prepare o seu consumidor para identificar `etiquetas.isTeste === "true"` e ramificar o processamento durante as validações. ### 📜 Logs de disparo ```bash curl -X GET "https://api.vehub.com.br/webhooks/019e0892-8d99-778c-9fa5-47bd07cd9ffb/disparos?pagina=1&quantidade=50" \ -H "Authorization: Bearer {seu_token}" \ -H "GrupoEconomico: {seu_grupo_economico}" ``` Cada tentativa de envio fica registrada com data, número da tentativa, duração, status HTTP, sucesso/falha, headers e payload enviados, resposta recebida, e a flag de teste. --- ## 🕒 Observações - Todos os timestamps estão em **UTC** (ISO 8601 com `Z`). - Os payloads usam **camelCase**. - Os eventos **não** transportam dados sensíveis do tomador além do necessário para identificar a operação. Para a ficha completa, consulte a proposta.