Skip to main content

Webhooks

Webhooks são notificações HTTP enviadas pela API do Faturamento Automático sempre que um evento relevante ocorre na sua Organização — assinatura criada, fatura paga, NF-e emitida, etc.

Em vez de fazer polling, você cadastra um endpoint HTTP público e recebe um POST com o payload do evento assim que ele acontece.

Cadastro

Gerencie endpoints em Dashboard → Configurações → API → Webhooks. Cada endpoint tem:

  • URL — destino HTTPS público do seu servidor.
  • Eventos assinados — lista dos event types que deseja receber. Se vazia, recebe todos.
  • Statusactive ou inactive.
  • Secret — string secreta usada para assinar cada entrega (HMAC-SHA256). Gerada automaticamente; pode ser rotacionada.
  • Auth headers — opcionalmente, cabeçalhos extras (Basic, Bearer, custom) injetados em cada requisição.

Entrega

Cada evento dispara uma requisição POST para a URL cadastrada:

POST /sua-url HTTP/1.1
Content-Type: application/json
User-Agent: Kobana-Webhook/1.0
X-Signature: t=1748438400,v1=8f2a...e91c
X-Event-Id: evt_01HXYZABC123
X-Event-Type: subscription.status_changed
X-Delivery-Id: del_01HABCDEF

{...payload JSON...}

Cabeçalhos

HeaderDescrição
X-SignatureAssinatura HMAC-SHA256. Formato: t=<timestamp_unix>,v1=<hex>.
X-Event-IdID único do evento. Use para deduplicar.
X-Event-TypeTipo do evento (ex.: invoice.paid).
X-Delivery-IdID único da tentativa de entrega.

Sucesso

Qualquer resposta 2xx em até 30 segundos marca a entrega como bem-sucedida. Qualquer outra coisa (timeout, 4xx, 5xx) é tratada como falha.

Retry

Falhas são reentregues com backoff exponencial:

TentativaAtraso
1imediato
2+1 min
3+5 min
4+30 min
5+2 h
6+6 h
7+24 h

Após 7 tentativas, a entrega é marcada como failed permanentemente. Eventos órfãos ficam disponíveis no dashboard para reenvio manual.

Validação da assinatura

Para garantir que a requisição veio do Faturamento Automático (e não foi adulterada), valide a assinatura usando o secret do endpoint.

Algoritmo:

  1. Extraia t e v1 do header X-Signature.
  2. Monte signed_payload = "{t}.{body_bruto}" (o body como string, sem reformatar JSON).
  3. Calcule expected = HMAC_SHA256(secret, signed_payload).hex().
  4. Compare expected com v1 em tempo constante.
  5. Opcionalmente, rejeite entregas com t mais antigo que 5 minutos para mitigar replay.

Exemplo (Node.js)

import crypto from 'node:crypto';

function verifyWebhook(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((p) => p.split('='))
);
const t = parts.t;
const v1 = parts.v1;
if (!t || !v1) return false;

const signedPayload = `${t}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');

const a = Buffer.from(v1, 'hex');
const b = Buffer.from(expected, 'hex');
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}

Exemplo (Python)

import hmac, hashlib

def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
parts = dict(p.split('=') for p in signature_header.split(','))
t, v1 = parts.get('t'), parts.get('v1')
if not t or not v1:
return False
signed = f"{t}.{raw_body.decode()}".encode()
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, v1)

Estrutura do payload

Todos os eventos compartilham o mesmo envelope:

{
"id": "evt_01HXYZABC123",
"type": "subscription.status_changed",
"created_at": "2026-05-20T12:00:00.000Z",
"environment": "production",
"version": "2026-03-01",
"data": { /* recurso completo */ },
"changes": { /* opcional, mudanças desde o estado anterior */ }
}
CampoDescrição
idID único do evento.
typeTipo do evento (ex.: invoice.paid).
created_atTimestamp ISO 8601 (UTC) em que o evento foi gerado.
environmentproduction ou sandbox.
versionVersão do schema do payload (string YYYY-MM-DD).
dataO recurso completo no estado atual.
changesPara eventos *.updated e *.status_changed, mapa campo: {from, to}. Pode estar ausente em eventos de criação/deleção.

Exemplos de payload por evento

Veja os exemplos completos navegando pelas páginas abaixo:

Boas práticas

  • Idempotência: use X-Event-Id para evitar processar duplicatas em caso de retry.
  • Resposta rápida: responda 2xx em até 30s. Enfile o trabalho pesado em fila assíncrona.
  • Versionamento: o campo version indica o schema. Trate campos novos como aditivos.
  • Validação obrigatória: sempre valide a assinatura antes de confiar no payload.
  • HTTPS: use TLS no endpoint. Endpoints HTTP são rejeitados em produção.
  • Lista de eventos: prefira assinar apenas os eventos que você processa, não *.