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 typesque deseja receber. Se vazia, recebe todos. - Status —
activeouinactive. - 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
| Header | Descrição |
|---|---|
X-Signature | Assinatura HMAC-SHA256. Formato: t=<timestamp_unix>,v1=<hex>. |
X-Event-Id | ID único do evento. Use para deduplicar. |
X-Event-Type | Tipo do evento (ex.: invoice.paid). |
X-Delivery-Id | ID ú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:
| Tentativa | Atraso |
|---|---|
| 1 | imediato |
| 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:
- Extraia
tev1do headerX-Signature. - Monte
signed_payload = "{t}.{body_bruto}"(o body como string, sem reformatar JSON). - Calcule
expected = HMAC_SHA256(secret, signed_payload).hex(). - Compare
expectedcomv1em tempo constante. - Opcionalmente, rejeite entregas com
tmais 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 */ }
}
| Campo | Descrição |
|---|---|
id | ID único do evento. |
type | Tipo do evento (ex.: invoice.paid). |
created_at | Timestamp ISO 8601 (UTC) em que o evento foi gerado. |
environment | production ou sandbox. |
version | Versão do schema do payload (string YYYY-MM-DD). |
data | O recurso completo no estado atual. |
changes | Para 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:
customer.db.createdcompany.db.updatedbilling_account.suspendedsubscription.status_changedinvoice.paidpayment.succeededpayment_method.expirednfe.issuedcredit.appliedproposal.acceptedplan.db.updatedproduct.archivedcoupon.redeemedservice_item.db.updated
Boas práticas
- Idempotência: use
X-Event-Idpara evitar processar duplicatas em caso de retry. - Resposta rápida: responda
2xxem até 30s. Enfile o trabalho pesado em fila assíncrona. - Versionamento: o campo
versionindica 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
*.