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

# Webhooks

> Eventos que o Spark envia via Svix, formato do payload, verificação de assinatura, portal do consumidor e como obter tipagem a partir do OpenAPI.

Além da API REST, o Spark pode **avisar sistemas externos em tempo real** quando algo relevante acontece na organização (por exemplo, uma mensagem nova ou um chat criado). Essas notificações são **webhooks de saída**: requisições `POST` HTTPS para URLs que você cadastra, com corpo JSON e infraestrutura de entrega, retentativas e assinatura gerenciadas pelo [Svix](https://www.svix.com/).

Esta página concentra o que integradores precisam saber no ecossistema Spark. Para o panorama geral de chaves e gateway, veja a [Introdução à API](/api-reference/introduction).

## O que são, na prática

Webhooks são a forma padrão de um serviço **avisar outro** sobre eventos. No Spark, cada evento vira uma mensagem enviada pelo Svix ao seu endpoint. O fluxo recomendado é:

1. Definir uma URL HTTPS que você controla (em geral **um endpoint por integração**, escutando os tipos de evento que interessam).
2. Cadastrar essa URL e filtrar os tipos de evento no **Consumer App Portal** (fornecido pelo Svix e acessível pelo painel do Spark).
3. No seu servidor, **validar a assinatura**, responder rápido com `2xx` e processar o negócio em fila ou worker, se precisar de mais tempo.

## Como configurar endpoints no Spark

O Spark não expõe a chave de API do Svix no navegador. Quem administra a organização abre [Configurações → Desenvolvedores](https://crmspark.com.br/dash/settings/developers), habilita o ambiente de desenvolvedores se ainda não estiver ativo, vai à **aba Webhooks** e usa o **Consumer App Portal** embutido: uma sessão de curta duração onde é possível **criar e editar endpoints**, ver o catálogo de eventos, testar entregas e inspecionar tentativas.

Isso corresponde ao fluxo descrito na documentação do Svix sobre o [Consumer App Portal](https://docs.svix.com/app-portal) e sobre [adicionar endpoints](https://docs.svix.com/receiving/using-app-portal/adding-endpoints).

## Formato da requisição que chega no seu servidor

Cada entrega é um `POST` com `Content-Type: application/json`. O corpo segue o contrato publicado no OpenAPI do gateway na chave **`x-webhooks`**: um objeto com duas propriedades:

| Campo   | Tipo   | Significado                                                              |
| ------- | ------ | ------------------------------------------------------------------------ |
| `event` | string | Nome do tipo de evento (veja tabela abaixo).                             |
| `data`  | objeto | Payload específico do evento (`tenantId`, `chatId`, `occurredAt`, etc.). |

Os cabeçalhos `svix-id`, `svix-timestamp` e `svix-signature` acompanham a requisição e são usados na **verificação de assinatura** (mesmo padrão descrito em [Introdução ao consumo de webhooks](https://docs.svix.com/receiving/introduction) e [Como verificar com as bibliotecas oficiais](https://docs.svix.com/receiving/verifying-payloads/how)).

## Eventos disponíveis hoje

| `event`             | Quando dispara                                                                                                                                                                                                                                                                                       |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `messages.received` | Nova mensagem **recebida** no chat (ex.: resposta do lead em WhatsApp, Instagram, Telegram ou WhatsApp Lite). Para mensagens de **áudio**, a entrega pode ser adiada até a transcrição ficar disponível ou até esgotarem as tentativas de transcrição (\~5 com backoff exponencial a partir de 20s). |
| `messages.sent`     | Mensagem **enviada** no chat (equipe, automação, API pública, etc.). Para mensagens de **áudio**, aplica-se o mesmo adiamento descrito em `messages.received`.                                                                                                                                       |
| `chats.created`     | **Novo chat** criado (novo contato ou conversa iniciada).                                                                                                                                                                                                                                            |

Cada `data` inclui `tenantId`, `chatId` e `occurredAt` (instante em ISO 8601). Eventos de mensagem incluem ainda `message` (registro serializado com texto, tipo, status, mídia, localização, remetente, metadados de template, etc.). Para áudio, quando possível, `message.transcription` virá preenchida no payload (em vez de `null`). `messages.received` inclui `entrypointId` (canal de entrada em que a mensagem foi recebida). `messages.sent` pode incluir `source` com um dos valores: `public_api`, `user`, `automation`, `campaign`, `addon`, `integration`, `business_hours`, `system`. `chats.created` inclui `platform` (`whatsapp`, `whatsapp_lite`, `instagram`, `telegram`) e, quando fizer sentido, `entrypointId`.

## Confirmar recebimento, tempo limite e CSRF

O Svix considera a entrega bem-sucedida quando seu endpoint responde com **código HTTP entre 200 e 299**, em geral dentro de um prazo da ordem de **15 segundos** (como descrito na [introdução ao consumo](https://docs.svix.com/receiving/introduction)). Se a lógica for pesada, o padrão recomendado é **persistir o payload bruto ou enfileirar** e retornar `2xx` logo em seguida.

Frameworks que aplicam **proteção CSRF** a todas as rotas `POST` costumam bloquear webhooks: desative CSRF **só** na rota pública que recebe o Svix, ou trate-a como rota de API sem cookie de sessão.

## Retentativas e idempotência

Falhas (timeout, `5xx`, resposta fora de `2xx`) disparam **novas tentativas** com backoff. Use o cabeçalho **`svix-id`** (e, se preferir, o identificador da mensagem dentro de `data`) para **deduplicar** processamento e ficar idempotente se a mesma entrega for repetida.

## Verificação de assinatura (obrigatória em produção)

A assinatura garante que o `POST` partiu da infraestrutura do Spark/Svix e que o corpo não foi alterado em trânsito. Regras importantes:

* Use o **corpo bruto da requisição** (string ou bytes exatamente como recebidos). Re-parsear JSON e serializar de novo costuma **invalidar** a assinatura.
* Passe os cabeçalhos `svix-id`, `svix-timestamp` e `svix-signature` para a biblioteca `Webhook` do pacote [`svix`](https://www.npmjs.com/package/svix) (ou equivalente na sua linguagem), junto com o **segredo do endpoint** (`whsec_…`) que o portal mostra para aquela URL.

Exemplos oficiais por framework (Next.js, Express, NestJS, FastAPI, etc.) estão em [How to Verify Webhooks](https://docs.svix.com/receiving/verifying-payloads/how).

## Tipagem e contratos para o seu código

O documento OpenAPI publicado em [gateway.crmspark.com.br/swagger-json](https://gateway.crmspark.com.br/swagger-json) inclui:

* **`x-webhooks`**: cada chave é o nome do evento (`messages.received`, …) com `requestBody` e exemplos.
* **`components.schemas`**: tipos como `SparkWebhookBodyMessagesReceived`, `MessagesReceivedWebhookPayload`, `SparkWebhookBodyMessagesSent`, `SparkWebhookBodyChatsCreated`, etc.

Com isso você pode:

* Usar os tipos exportados pelo SDK [`sparkcrm`](https://www.npmjs.com/package/sparkcrm) (`SparkWebhookBody`, etc.) — veja [TypeScript — webhooks e tipos](/sdks/typescript/webhooks-e-tipos).
* Gerar cliente ou tipos com **[Orval](https://orval.dev/)**, **openapi-typescript** ou outra ferramenta apontando para a URL do Swagger do gateway.
* Conferir payloads e campos obrigatórios direto na **referência interativa** ao lado (grupo Webhooks).

Quem mantém fork ou monorepo junto ao Spark pode, em TypeScript, reutilizar os mesmos contratos do servidor: o pacote interno `@spark/gateway-kit` exporta constantes (`GATEWAY_WEBHOOK_EVENT_*`), catálogo (`GATEWAY_WEBHOOK_EVENT_CATALOG`) e schemas Zod (`messagesReceivedWebhookPayloadSchema`, `messagesSentWebhookPayloadSchema`, `chatsCreatedWebhookPayloadSchema`) alinhados ao OpenAPI.

## Leitura adicional

* [Documentando webhooks](https://docs.svix.com/documenting-webhooks) — seções recomendadas para docs de produto (intro, eventos, testes, assinatura, retries, troubleshooting).
* [Consumer App Portal](https://docs.svix.com/app-portal) — sessão por URL, incorporação em iframe, white label.
* [Introdução ao consumo](https://docs.svix.com/receiving/introduction) — modelo mental `POST` + `2xx` + verificação.
* [Como verificar payloads](https://docs.svix.com/receiving/verifying-payloads/how) — uso do corpo cru e bibliotecas oficiais.
