Webhooks
Cadastre endpoints HTTPS públicos no portal (Webhooks), por ambiente e tipo de evento. O segredo de assinatura (whsec_…) é exibido uma única vez.
Eventos
| Tipo | Quando |
|---|---|
search.completed |
busca terminou (qualquer estado final) |
monitoring.updated |
novos andamentos no processo monitorado |
monitoring.paused |
monitoramento pausado (saldo/fonte) |
payment.confirmed |
recarga ou fatura confirmada |
invoice.closed |
fatura pós-paga fechada |
webhook.test |
teste disparado pelo portal |
Assinatura e anti-replay
Cabeçalhos: Odjud-Event-Id, Odjud-Event-Type, Odjud-Signature: t=<unix>,v1=<hex>.
v1 = HMAC_SHA256(segredo, "<t>.<corpo bruto>"). Durante a rotação do segredo, pode haver dois v1 (aceite qualquer um).
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(header.match(/t=(\d+)/)[1]);
if (Math.abs(Date.now() / 1000 - t) > 300) return false; // anti-replay
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return header.split(",").filter((p) => p.startsWith("v1=")).some((p) => crypto.timingSafeEqual(Buffer.from(p.slice(3)), Buffer.from(expected)));
}
Deduplique por Odjud-Event-Id e responda 2xx rapidamente.
Entrega
- Até 8 tentativas com backoff exponencial e jitter (≈30 s, 1 min, 2 min… até 6 h). Esgotadas, a entrega fica DEAD, visível no portal.
- Redirecionamentos não são seguidos.
- Destinos são validados contra SSRF: HTTPS, porta 443/8443, DNS resolvido para IP público (redes privadas, loopback, link-local e metadados de nuvem são recusados), revalidado na conexão.