Pular para o conteúdo

Webhooks

Webhooks permitem que o Sentinex notifique sua aplicação quando eventos relevantes acontecem: alerta criado, KYC concluído, transação reanalisada. Substitui polling por push.

Event typeQuando disparaPayload principal
customer.createdPOST /vasp/customersobjeto customer
customer.updatedmudança de campo persistidocustomer + changed_fields
customer.deletedDELETE /vasp/customers/:id (LGPD soft-delete){ id, deleted_at }
wallet.linkedPOST /vasp/walletswallet + customer_id
wallet.unlinkeddesvincular walletwallet + razão
kyc.completedtier muda para STANDARD ou ENHANCEDcustomer + kyc_tier + completed_at
kyc.review_requiredExato/bureau retornou inconsistênciacustomer + reasons[]
transaction.analyzedKYT processou transaçãotransaction + decision + score
alert.createdregra disparou alerta novoalert
alert.escalatedanalista escaloualert + escalation event
alert.resolvedanalista resolveualert + resolution
case.openedcaso compliance abertocase
sar.submittedCOAF SAR enviadosar metadata

Wildcard: events: [] (array vazio) na subscription recebe todos.

Terminal window
curl -X POST https://api.crypto.sentinexrisk.com/api/v1/vasp/webhooks \
-H "X-API-Key: $SENTINEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target_url": "https://hooks.suaempresa.com.br/sentinex",
"events": ["alert.created", "alert.escalated", "kyc.completed"],
"description": "Pager + dashboard ops"
}'
# Requer o escopo vasp:webhooks:manage. O secret HMAC é retornado UMA
# única vez na resposta 201. A rota /admin/outbound-webhooks/subscriptions
# é a equivalente do dashboard (JWT).

Resposta 201:

{
"success": true,
"data": {
"id": "wh_01HVZ…",
"url": "https://hooks.suaempresa.com.br/sentinex",
"secret": "whsec_<EXEMPLO_NAO_USE_EM_PROD>",
"events": ["alert.created", "alert.escalated", "kyc.completed"],
"created_at": "2026-05-18T14:32:11Z"
}
}

Toda requisição vem com:

POST /sentinex HTTP/1.1
Content-Type: application/json
X-Sentinex-Event: alert.created
X-Sentinex-Timestamp: 1747584000
X-Sentinex-Signature: t=1747584000,v1=5d3b7a9e1c4f2d6b8a7e9c3d5f1b2a4e6c8d7f9b1a3e5c7d9b2a4f6e8c1d3b5a
X-Sentinex-Delivery: dlv_01HVZ…
{ "event": "alert.created", "data": { ... } }

A assinatura é HMAC_SHA256(secret, "{timestamp}.{raw_body}").

import crypto from 'crypto';
function verifySentinexWebhook(req, secret) {
const sigHeader = req.headers['x-sentinex-signature'];
const timestamp = req.headers['x-sentinex-timestamp'];
const rawBody = req.rawBody; // string, NÃO o JSON parsed
// Anti-replay: rejeita se mais de 5 min de tolerância
if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) {
throw new Error('Timestamp fora da janela');
}
const parts = Object.fromEntries(sigHeader.split(',').map(p => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
// timingSafeEqual previne timing attack
const ok = crypto.timingSafeEqual(
Buffer.from(parts.v1, 'hex'),
Buffer.from(expected, 'hex'),
);
if (!ok) throw new Error('Assinatura inválida');
}
TentativaAtraso após falha anterior
imediata
10s
60s
5min
Após 3 falhasmove para DLQ, status = dead

Falha = resposta HTTP fora de 2xx OU timeout > 5s.

Após 5 falhas consecutivas em uma subscription, ela é auto-pausada (active: false) para prevenir spam. Você recebe email + evento subscription.paused.

Eventos que falharam definitivamente ficam disponíveis em:

Terminal window
GET /api/v1/admin/outbound-webhooks/subscriptions/{id}/dlq

Replay manual:

Terminal window
POST /api/v1/admin/outbound-webhooks/subscriptions/{id}/dlq/{delivery_id}/replay
Terminal window
POST /api/v1/admin/outbound-webhooks/subscriptions/{id}/rotate

Retorna novo secret. O antigo continua válido por 24h para você atualizar consumers sem downtime. Após 24h, antigo é revogado.

  1. Responda 2xx em <2s: processamento pesado deve ir para fila assíncrona
  2. Idempotência por X-Sentinex-Delivery: o mesmo evento pode chegar duas vezes (rede falha entre nossa app e seu consumer)
  3. Endpoint HTTPS obrigatório (HTTP recusado pelo Sentinex)
  4. Sem autenticação extra: a assinatura HMAC já é a auth
  5. Logue X-Sentinex-Delivery: facilita o suporte cruzar logs

Use ngrok ou similar e configure subscription apontando para o tunnel:

Terminal window
ngrok http 4000
# https://abc123.ngrok.io → seu localhost:4000

No console Webhooks → Test Delivery você pode disparar evento sintético sem causar efeito de negócio.