Webhooks (Outbound): Receba Eventos de Entrega
🔗 Integração bidirecional: Receba notificações em tempo real sobre entregas, aberturas e cliques
Webhooks permitem que a Notifica chame sua API quando eventos acontecem. Use para:
- Atualizar status de notificações no seu banco
- Disparar ações baseadas em entrega
- Sincronizar analytics
- Implementar lógica de retry customizada
Como funcionam
- Evento acontece (ex: email entregue)
- Notifica faz POST para sua URL
- Sua API processa e responde 200 OK
- Notifica marca como entregue
Se sua API retornar erro, a Notifica faz retry automático.
Criando um webhook
curl -X POST https://app.usenotifica.com.br/v1/webhooks \
-H "Authorization: Bearer nk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.empresa.com.br/webhooks/notifica",
"events": [
"notification.sent",
"notification.delivered",
"notification.failed",
"notification.opened",
"notification.clicked",
"notification.bounced",
"notification.complained"
],
"secret": "whsec_minha_chave_secreta_32_chars",
"description": "Webhook principal de eventos",
"active": true
}'
Resposta:
{
"id": "wh_abc123",
"url": "https://api.empresa.com.br/webhooks/notifica",
"events": ["notification.sent", "notification.delivered", ...],
"secret": "whsec_***",
"active": true,
"created_at": "2024-01-15T10:00:00Z"
}
Eventos disponíveis
Notificações
| Evento | Descrição | Dados incluídos |
|---|---|---|
notification.created | Notificação criada | notification, subscriber |
notification.sent | Enviada ao provedor | notification, provider |
notification.delivered | Confirmada entrega | notification, delivered_at |
notification.failed | Falha na entrega | notification, error |
notification.bounced | Email/telefone inválido | notification, bounce_reason |
notification.opened | Email aberto | notification, opened_at, ip, user_agent |
notification.clicked | Link clicado | notification, clicked_at, url |
notification.complained | Marcado como spam | notification, complaint_type |
Workflows
| Evento | Descrição |
|---|---|
workflow.triggered | Workflow iniciado |
workflow.step.completed | Step concluído |
workflow.step.failed | Step falhou |
workflow.completed | Workflow finalizado |
Inbox
| Evento | Descrição |
|---|---|
inbox.notification.received | Nova notificação no inbox |
inbox.notification.read | Notificação marcada como lida |
Payload do webhook
Exemplo: notification.delivered
{
"id": "evt_xyz789",
"type": "notification.delivered",
"created_at": "2024-01-15T14:30:05Z",
"data": {
"notification": {
"id": "not_abc123",
"status": "delivered",
"channel": "email",
"to": "[email protected]",
"subject": "Seu pedido foi enviado!",
"template": "order_shipped",
"external_id": "order_456"
},
"subscriber": {
"id": "sub_def456",
"external_id": "user_789",
"email": "[email protected]"
},
"delivery": {
"delivered_at": "2024-01-15T14:30:05Z",
"provider": "sendgrid",
"message_id": "<[email protected]>"
}
}
}
Exemplo: notification.failed
{
"id": "evt_abc456",
"type": "notification.failed",
"created_at": "2024-01-15T14:30:02Z",
"data": {
"notification": {
"id": "not_abc123",
"status": "failed",
"channel": "email"
},
"error": {
"code": "invalid_recipient",
"message": "550 5.1.1 The email account does not exist",
"provider": "sendgrid",
"attempt": 3,
"will_retry": false
}
}
}
Verificando assinatura
Proteja seu endpoint verificando que o webhook vem realmente da Notifica:
Node.js
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
// Express middleware
app.post('/webhooks/notifica', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-notifica-signature'];
const payload = req.body;
const secret = process.env.NOTIFICA_WEBHOOK_SECRET;
if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
// Processar evento
handleWebhook(event);
res.status(200).send('OK');
});
Python
import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(
signature.replace('sha256=', ''),
expected
)
# Flask
@app.route('/webhooks/notifica', methods=['POST'])
def webhook():
signature = request.headers.get('X-Notifica-Signature', '')
secret = os.getenv('NOTIFICA_WEBHOOK_SECRET')
if not verify_webhook_signature(request.data, signature, secret):
return 'Invalid signature', 401
event = request.json
handle_webhook(event)
return 'OK', 200
Processando eventos
Node.js completo
// services/webhookProcessor.js
class WebhookProcessor {
async process(event) {
switch (event.type) {
case 'notification.delivered':
await this.handleDelivered(event.data);
break;
case 'notification.failed':
await this.handleFailed(event.data);
break;
case 'notification.opened':
await this.handleOpened(event.data);
break;
case 'notification.clicked':
await this.handleClicked(event.data);
break;
case 'notification.bounced':
await this.handleBounced(event.data);
break;
default:
console.log(`Evento não tratado: ${event.type}`);
}
}
async handleDelivered({ notification }) {
await db.notifications.update(notification.id, {
status: 'delivered',
delivered_at: new Date()
});
// Atualizar métricas do usuário
await db.users.incrementMetric(
notification.subscriber.external_id,
'emails_delivered'
);
}
async handleFailed({ notification, error }) {
await db.notifications.update(notification.id, {
status: 'failed',
error_code: error.code,
error_message: error.message
});
// Se falhou permanentemente, notificar usuário ou equipe
if (!error.will_retry) {
await this.alertFailedNotification(notification, error);
}
}
async handleBounced({ notification, error }) {
// Marcar email como inválido
await db.subscribers.update(
notification.subscriber.id,
{ email_valid: false, bounce_reason: error.message }
);
// Adicionar à lista de supressão
await db.suppressions.create({
email: notification.to,
reason: 'bounce',
permanent: true
});
}
async handleOpened({ notification, delivery }) {
await db.notifications.update(notification.id, {
opened_at: delivery.opened_at,
open_ip: delivery.ip,
open_user_agent: delivery.user_agent
});
}
async handleClicked({ notification, delivery }) {
await db.click_events.create({
notification_id: notification.id,
url: delivery.url,
clicked_at: delivery.clicked_at
});
}
}
module.exports = new WebhookProcessor();
Retry e garantias de entrega
Comportamento de retry
Se seu endpoint retornar erro:
| Tentativa | Delay | Ação se falhar |
|---|---|---|
| 1 | Imediato | Retry |
| 2 | 5 minutos | Retry |
| 3 | 30 minutos | Retry |
| 4 | 2 horas | Retry |
| 5+ | 6 horas | Descartar |
Verificar deliveries perdidos
curl https://app.usenotifica.com.br/v1/webhooks/wh_abc123/deliveries \
-H "Authorization: Bearer nk_live_sua_chave"
Testando webhooks
Teste via dashboard
Vá em Webhooks → Testar e envie um evento de teste.
Teste via API
curl -X POST https://app.usenotifica.com.br/v1/webhooks/wh_abc123/test \
-H "Authorization: Bearer nk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"event": "notification.delivered",
"override_url": "https://webhook.site/seu-uuid-aqui"
}'
Ferramentas de teste
- webhook.site — URLs temporárias para teste
- ngrok — Expor localhost para testes locais
Listando e gerenciando webhooks
Listar webhooks
curl https://app.usenotifica.com.br/v1/webhooks \
-H "Authorization: Bearer nk_live_sua_chave"
Atualizar webhook
curl -X PUT https://app.usenotifica.com.br/v1/webhooks/wh_abc123 \
-H "Authorization: Bearer nk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"events": ["notification.delivered", "notification.failed"],
"url": "https://nova-url.com.br/webhook"
}'
Desativar webhook
curl -X PUT https://app.usenotifica.com.br/v1/webhooks/wh_abc123 \
-H "Authorization: Bearer nk_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{"active": false}'
Deletar webhook
curl -X DELETE https://app.usenotifica.com.br/v1/webhooks/wh_abc123 \
-H "Authorization: Bearer nk_live_sua_chave"
Boas práticas
✅ Faça
- Verifique assinatura de todos os webhooks
- Responda 200 OK rapidamente (< 5s)
- Processe webhook em background (fila)
- Idempotência: mesmo evento pode chegar 2x
- Logue todos os webhooks recebidos
❌ Não faça
- Processamento síncrono pesado no handler
- Depender de ordem dos eventos
- Ignorar erros de assinatura
- Retornar 4xx para erros temporários
FAQ
Q: Posso ter múltiplos webhooks?
A: Sim! Máximo 10 por workspace.
Q: Webhooks são garantidos?
A: Fazemos retry mas não garantimos 100%. Use polling de backup para dados críticos.
Q: Qual o timeout?
A: 30 segundos. Responda 200 OK imediatamente e processe em background.
Q: Eventos chegam em ordem?
A: Não garantimos ordenação. Use created_at para ordenar.
Q: Posso filtrar por notificação específica?
A: Não no webhook. Filtre no seu código após receber.
Próximo passo
Explore o Analytics para visualizar métricas de entrega e otimizar suas notificações.