Webhooks
EstávelReceba eventos da Riskora no seu sistema (outbound) ou envie eventos do seu sistema pra Riskora (inbound). Em ambas as direções, a comunicação é HTTP POST assinada com HMAC-SHA256.
Duas direções
O sistema de webhooks da Riskora suporta as duas pontas da integração transacional. Headers, formato de assinatura, retry e idempotência seguem contratos públicos versionados — mudanças com impacto são comunicadas com antecedência aos clientes integrados.
Outbound
Riskora envia POST assinado pro seu sistema sempre que acontece uma mudança na entidade que você assinou (criação, alteração, finalização, etc.).
Inbound
Seu sistema envia POST assinado pra um endpoint da Riskora; o payload dispara um processo configurado (ex: atualizar histórico do avaliado, criar análise).
Outbound · Riskora → seu sistema
Quando usar
A API REST permite consultar o estado de qualquer registro a qualquer momento, mas consultar em loop é caro. Webhook é o canônico pra reagir no segundo que algo muda.
- Checkout transacional: cliente esperando aprovação. Receba a finalização da análise e libere o pedido automaticamente.
- Sincronização de ERP: mantenha limite de crédito e score do avaliado no seu ERP sempre atualizado, sem cron diário.
- Alerta de equipe: análise caiu em revisão manual; notifique o analista de plantão via Slack, Teams ou ticket.
- Notificação ao vendedor: aviso imediato quando a análise da carteira é aprovada, rejeitada ou precisa de reenvio de documentos.
Como assinar eventos
A assinatura é por tabela + tipo de gatilho, não por evento semântico. Você define quais entidades quer monitorar e qual mudança dispara a notificação. O payload pode usar um template customizado pra entregar JSON limpo, com nomes e estrutura que façam sentido pro seu sistema.
| Código | Quando dispara | Uso típico na Riskora |
|---|---|---|
TAN | Registro criado | Análise nova, avaliado novo |
TAC | Registro alterado | Mudança de status da análise, atualização de score do avaliado |
TAD | Registro removido | Auditoria de exclusão (raro em entidades de avaliação) |
DACO | Documento finalizado | Reservado pra fluxos transacionais |
DAVO | Documento anulado | Reservado pra fluxos transacionais |
DACL | Documento encerrado | Reservado pra fluxos transacionais |
Pra avaliações, os gatilhos relevantes são TAN e TAC em Z_Eval_Analysis e Z_Evaluee. O gatilho dispara em qualquer alteração da tabela; filtros por valor (ex: só quando z_EvalStatus = AP) ficam no seu lado, lendo o payload.
Exemplo · Notificação de finalização de análise
Cenário: você quer ser notificado sempre que uma análise muda de estado, com payload contendo só os campos do seu interesse.
| Campo | Valor |
|---|---|
| Tabela | Z_Eval_Analysis |
| Gatilho | TAC |
| URL de destino | https://erp.cliente.com/webhooks/riskora |
| Assinatura HMAC | Habilitada (padrão recomendado) |
Cada @ColumnName@ é substituído pelo valor do registro alterado. Sem template, o plugin envia o registro inteiro com todas as colunas da tabela.
{
"analysis_value": "@Value@",
"reference_no": "@z_ReferenceNo@",
"evaluee_id": @Z_Evaluee_ID@,
"status": "@z_EvalStatus@",
"final_score": @z_FinalScore@,
"tier": "@z_TierValue@",
"approved_limit": @z_ApprovedLimit@,
"calculated_limit": @z_CalculatedLimit@,
"risk_level": "@z_RiskLevel@",
"ai_recommendation": "@z_AIRecommendation@"
}POST /webhooks/riskora HTTP/1.1
Host: erp.cliente.com
Content-Type: application/json
webhook-id: msg_01hxyza1b2c3d4e5f6g7h8j9k0
webhook-timestamp: 1712587330
webhook-signature: v1,a591a6d40bf42040eb...
{
"analysis_value": "RK-PJ_AVANCADA_IC943",
"reference_no": "PED-2026-1234",
"evaluee_id": 1000042,
"status": "AP",
"final_score": 782,
"tier": "B",
"approved_limit": 45000,
"calculated_limit": 50000,
"risk_level": "L",
"ai_recommendation": "APROVAR"
}No seu lado, filtre por status em ["AP", "RJ", "CA", "EX"] pra reagir só nas finalizações. Outras transições intermediárias (ex: DR → IP, IP → MR) chegam pelo mesmo gatilho.
Segurança · HMAC-SHA256
Toda requisição com assinatura habilitada vai assinada. Seu endpoint deve validar a assinatura antes de processar — sem isso, qualquer um que descobrir a URL pode forjar eventos.
| Header | Formato | Exemplo |
|---|---|---|
webhook-id | msg_<uuid> | msg_01hxyza1b2c3d4e5f6g7h8j9k0 |
webhook-timestamp | unix epoch (segundos) | 1712587330 |
webhook-signature | v1,<base64> (espaço-separado em rotação) | v1,a591a6d40bf42040eb... |
O secret é gerado no painel com prefixo whsec_. Pra validar, decodifique o base64 do que vem depois do prefixo e use como chave HMAC.
import crypto from 'crypto';
// Secret recebido no setup, sem o prefixo whsec_
const SECRET_BASE64 = process.env.RISKORA_WEBHOOK_SECRET;
const secretKey = Buffer.from(SECRET_BASE64, 'base64');
export async function handleWebhook(req) {
// 1. Lê o RAW body antes de qualquer parse
const rawBody = await req.text();
// 2. Verifica janela de 5 minutos (anti-replay)
const timestamp = req.headers.get('webhook-timestamp');
const age = Math.floor(Date.now() / 1000) - Number(timestamp);
if (Math.abs(age) > 300) {
return new Response('Timestamp expirado', { status: 400 });
}
// 3. Reconstrói o conteúdo assinado
const msgId = req.headers.get('webhook-id');
const signed = `${msgId}.${timestamp}.${rawBody}`;
// 4. Calcula a assinatura esperada
const expected = crypto
.createHmac('sha256', secretKey)
.update(signed)
.digest('base64');
// 5. Compara em tempo constante (suporta rotação de secret)
const received = req.headers.get('webhook-signature') ?? '';
const ok = received.split(' ').some(sig => {
const value = sig.startsWith('v1,') ? sig.slice(3) : sig;
try {
return crypto.timingSafeEqual(
Buffer.from(value, 'base64'),
Buffer.from(expected, 'base64')
);
} catch { return false; }
});
if (!ok) return new Response('Assinatura inválida', { status: 401 });
// 6. OK: processar
const payload = JSON.parse(rawBody);
// ... lógica do seu sistema
return new Response('ok', { status: 200 });
}Retry e idempotência
Entrega at-least-once. Sucesso é qualquer resposta HTTP 2xx; falha (timeout ou 5xx) reagenda nova tentativa. Após o teto de tentativas, a inscrição pode ser auto-pausada e a entrega marcada como abandonada.
| Tentativa | Delay | Janela acumulada |
|---|---|---|
| 1 | imediato | 0s |
| 2 | +5s | 5s |
| 3 | +5min | 5min 5s |
| 4 | +30min | 35min 5s |
| 5 | +2h | 2h 35min |
| 6 | +5h | 7h 35min |
| 7 | +10h | 17h 35min |
| 8 | +14h | 1d 7h 35min |
| 9 | +20h | 2d 3h 35min |
| 10 | +24h | 3d 3h 35min |
| — | desiste | marca delivery_failed |
Cada tentativa aplica jitter de ±15%. O teto e o timeout HTTP são configuráveis via SysConfig; o default é razoável pra grande maioria dos casos.
Idempotência é responsabilidade do consumidor: o mesmo evento pode chegar mais de uma vez (retry após timeout do seu lado, por exemplo). Sempre persista o webhook-id processado e ignore duplicatas.
Inbound · seu sistema → Riskora
Quando usar
Quando seu sistema é a fonte de um evento que precisa refletir na Riskora — uma compra fechada, um cliente que mudou de status, um pagamento confirmado. Ao invés de fazer várias chamadas REST sequenciais, você posta um JSON num endpoint e a Riskora dispara o processo certo.
- Atualização de histórico do avaliado: seu ERP fecha um pedido; envia o evento e a Riskora atualiza
z_LastPurchaseDate,z_TotalPurchases12m,z_AverageTicket. - Notificação de pagamento: sistema de cobrança confirma quitação; a Riskora reflete em
z_PaymentBehavior. - Disparo de análise via evento: CRM detecta lead qualificado; chama o webhook e a Riskora cria a análise correspondente.
Como funciona
Cada caso de uso de inbound é uma combinação endpoint + processo:
- 1.Você define com a equipe Riskora o caso de uso: qual payload o seu sistema vai enviar e que ação isso dispara na plataforma.
- 2.A Riskora cria o processo que recebe o payload (nativo ou via Groovy/Java) e configura o endpoint
/api/v1/webhooks/{key}com seu próprio secret. - 3.Você recebe a URL do endpoint, o secret pra assinar e (opcional) a lista de IPs/CIDR que será aceita.
- 4.Seu sistema posta JSON assinado; a Riskora valida assinatura, detecta duplicata pelo
webhook-id, e roda o processo.
Verificação de assinatura é altamente recomendada e fica habilitada por padrão. Sem assinatura, qualquer requisição ao endpoint é processada — só faz sentido em ambiente fechado com lista de IPs muito restrita.
Exemplo · ERP atualizando histórico de compra
Cenário: cada vez que seu ERP fecha um pedido, você quer que a Riskora atualize o histórico do avaliado pra a próxima análise já considerar o dado novo.
POST https://app.riskora.ai/api/v1/webhooks/erp-pedido-fechado{
"evaluee_document": "13823508000131",
"purchase_date": "2026-05-08",
"purchase_amount": 18500.00,
"payment_status": "PAID",
"external_order_id": "PED-2026-1234"
}SECRET_BASE64="<parte depois do whsec_>"
BODY='{"evaluee_document":"13823508000131","purchase_date":"2026-05-08","purchase_amount":18500.00,"payment_status":"PAID","external_order_id":"PED-2026-1234"}'
MSG_ID="msg_$(uuidgen)"
TIMESTAMP=$(date +%s)
SIGNATURE=$(printf '%s.%s.%s' "$MSG_ID" "$TIMESTAMP" "$BODY" \
| openssl dgst -sha256 -hmac "$(printf '%s' "$SECRET_BASE64" | base64 -d)" -binary \
| base64)
curl -X POST https://app.riskora.ai/api/v1/webhooks/erp-pedido-fechado \
-H "Content-Type: application/json" \
-H "webhook-id: $MSG_ID" \
-H "webhook-timestamp: $TIMESTAMP" \
-H "webhook-signature: v1,$SIGNATURE" \
-d "$BODY"| Status | Body | Significado |
|---|---|---|
| 200 | {"status":"ok"} | Processo executou com sucesso |
| 200 | {"status":"duplicate"} | Mesmo webhook-id já processado; idempotente |
| 400 | erro | Header obrigatório ausente ou timestamp expirado |
| 401 | erro | Assinatura inválida |
| 403 | erro | IP de origem não autorizado |
| 404 | erro | Endpoint key inexistente |
webhook-id é obrigatório quando a verificação de assinatura está habilitada. Use UUID/ULID — repostar com o mesmo ID retorna duplicate sem re-rodar o processo.
Limites e considerações
- •Tamanho do payload: hoje limitado a 4000 caracteres por chamada inbound. Pra volumes maiores, fragmentar ou usar a API REST diretamente.
- •Conteúdo: apenas
application/jsoné suportado. Binários não são aceitos. - •Idempotência: o controle pelo
webhook-idsó funciona se a verificação de assinatura estiver habilitada. Forte recomendação de manter habilitada. - •IP allowlist: opcional, mas recomendada se o seu sistema sai de IPs conhecidos. Aceita CIDR (ex:
200.10.0.0/24).
Quero integrar. E agora?
- 1.Entre em contato pelo formulário informando se precisa de outbound, inbound ou ambos.
- 2.Pra outbound: você descreve as entidades e gatilhos que quer assinar (e, se quiser, o template de payload). A Riskora configura a inscrição e devolve URL de destino + secret pra você usar do seu lado.
- 3.Pra inbound: você descreve o caso de uso (qual evento dispara qual ação na Riskora, formato do payload). A Riskora configura o processo, o endpoint e devolve URL + secret + IPs autorizados.
- 4.Validação em ambiente de homologação com eventos sintéticos antes da virada pra produção.
Ainda com dúvidas?
A equipe técnica pode revisar o caso de uso e recomendar a melhor estratégia (API, webhook outbound, inbound ou combinação).