Skip to content

Webhooks ​

Em vez de você consultar o Edusati para saber se algo mudou, o Edusati chama o seu servidor quando acontece: uma resposta foi finalizada, um convite foi aberto, uma meta foi atingida.

Resposta finalizada
      │
      ▼
  Edusati  ──── POST assinado ────►  https://seu-servidor.com/edusati
                                     └─ você responde 2xx

Configurar um endpoint ​

No painel, em Integrações › Webhooks:

  1. Nova assinatura
  2. Informe a URL — precisa ser https:// e acessível pela internet
  3. Escolha os eventos que interessam (ou * para todos)
  4. Salve e revele o segredo — é com ele que você valida a assinatura
  5. Clique em Testar: dispara um evento ping e você vê o resultado no log

O log de entregas fica na mesma tela: status, código HTTP de resposta, tentativas e o payload enviado.

O formato ​

Todo POST tem o mesmo envelope. Só type e data mudam:

json
{
  "id": "8f4c1e2a-…",
  "type": "response.created",
  "version": 1,
  "occurredAt": "2026-07-28T13:45:12.001Z",
  "companyId": "c0ffee00-…",
  "data": {
    "formId": "f1a2b3c4-…",
    "formName": "Pesquisa de satisfação — Julho",
    "formSlug": "satisfacao-julho",
    "responseId": "r1a2b3c4-…",
    "inviteId": null,
    "completedAt": "2026-07-28T13:45:11.980Z",
    "respondent": { "name": "Ana Prado", "email": "ana@exemplo.com", "phone": null, "externalId": "MAT-4471" },
    "answers": { "q_nps": 9, "q_comentario": "Atendimento muito rápido" }
  }
}
CampoO que é
idId do evento. É por ele que você deduplica
typeUm dos tipos do catálogo
versionVersão do payload — ver compatibilidade
occurredAtQuando o fato aconteceu (ISO 8601 UTC)
companyIdEmpresa de origem
dataConteúdo específico do tipo

As respostas viajam dentro do evento de propósito: é o que dispensa uma segunda chamada só para descobrir o que a pessoa respondeu.

As três regras ​

1. Valide a assinatura ​

Sua URL é pública; qualquer um pode fazer POST nela. A assinatura é o que prova que a requisição veio de nós. Detalhes e código pronto em Assinatura.

Nunca confie no conteúdo de um POST cuja assinatura você não verificou.

2. Deduplique pelo id ​

A entrega é pelo menos uma vez. Uma falha de rede entre o seu 200 e o nosso registro faz a mesma entrega ser tentada de novo — com o mesmo id de evento.

js
if (await jaProcessei(evento.id)) return res.sendStatus(200);
await processar(evento);
await marcarProcessado(evento.id);

Guarde os ids por pelo menos alguns dias. Se o seu processamento já é idempotente por natureza (um UPSERT pela chave do registro), isso basta e você não precisa da tabela de ids.

X-Edusati-Delivery não serve para deduplicar

Esse header identifica a tentativa, e muda a cada retry. O id do corpo é o que se repete — é ele que você guarda.

3. Responda rápido ​

Responda 2xx assim que receber e processe depois, fora do ciclo da requisição. O timeout é de 10 segundos; passar disso conta como falha e agenda retry, mesmo que você tenha processado tudo direitinho.

js
app.post('/edusati', async (req, res) => {
  if (!assinaturaValida(req)) return res.sendStatus(401);
  await fila.enfileirar(req.body);   // processamento pesado sai daqui
  res.sendStatus(200);               // confirma antes de trabalhar
});

O que acontece quando falha ​

Resumo — o detalhe está em Entrega e falhas:

  • Qualquer 2xx confirma o recebimento
  • Qualquer outra resposta, timeout, erro de DNS ou de TLS agenda retry com backoff (30s, 1min, 2min… até 1h), num total de 5 tentativas
  • 410 Gone desativa o endpoint imediatamente — use quando ele acabou de vez
  • 20 falhas consecutivas desativam o endpoint automaticamente
  • Redirecionamentos não são seguidos: mudou de endereço, edite o endpoint

Compatibilidade ​

Vamos acrescentar campos em data ao longo do tempo, e isso não bumpa a version. Seu consumidor precisa tolerar campos que não conhece — não valide o payload com um schema estrito que rejeite propriedades extras.

Mudança de semântica de um campo existente, essa sim, sobe a version. Você não faz deploy junto com a gente, então esse é o contrato: aditivo é silencioso, quebra é versionada.

Da mesma forma, tipos novos de evento podem aparecer. Se você assinou *, ignore com elegância o que não reconhece:

js
const handler = handlers[evento.type];
if (!handler) return res.sendStatus(200);   // 200, não 400 — não é erro dele

Privacidade ​

O payload de response.created inclui as respostas e os dados do respondente — ou seja, dados pessoais saem do Edusati e entram na sua infraestrutura. Trate-os com o mesmo cuidado que trataria dados coletados por você: TLS, acesso restrito, prazo de descarte.

Do nosso lado, o log de entregas (com o payload) tem prazo curto de retenção.

Próximos passos ​

Documentação da API pública do Edusati