Documentation Index
Fetch the complete documentation index at: https://docs.vistum.com.br/llms.txt
Use this file to discover all available pages before exploring further.
Por que verificar
Qualquer pessoa pode enviar uma requisição POST para a sua URL de webhook. A assinatura HMAC-SHA256 garante que a requisição veio do Vistum e que o payload não foi adulterado.
Sempre verifique a assinatura antes de processar um evento. Ignorar esta etapa expõe sua integração a ataques de replay e spoofing.
Como funciona
Cada requisição de webhook inclui o header:
X-Vistum-Signature: t=1746666000,v1=a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
t — Unix timestamp da entrega (em segundos)
v1 — HMAC-SHA256 em hex
String assinada:
{timestamp}.{body_json_raw}
O HMAC é calculado com o secret do webhook (gerado na criação) como chave.
Verificação por linguagem
import crypto from "crypto"
function verifyWebhook(rawBody, signature, secret) {
const parts = Object.fromEntries(
signature.split(",").map(p => p.split("="))
)
const timestamp = parts["t"]
const receivedHmac = parts["v1"]
if (!timestamp || !receivedHmac) return false
// Rejeita eventos com mais de 5 minutos (proteção contra replay)
const age = Math.abs(Date.now() / 1000 - Number(timestamp))
if (age > 300) return false
const signedString = `${timestamp}.${rawBody}`
const expected = crypto
.createHmac("sha256", secret)
.update(signedString)
.digest("hex")
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(receivedHmac)
)
}
// Express / Next.js
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-vistum-signature"] ?? ""
const valid = verifyWebhook(req.body.toString(), signature, process.env.WEBHOOK_SECRET)
if (!valid) return res.status(401).json({ error: "Invalid signature" })
const event = JSON.parse(req.body)
console.log("Evento recebido:", event.event)
res.json({ ok: true })
})
Rotação do secret
Se o seu secret de webhook for comprometido, você pode rotacioná-lo sem interromper as entregas:
- Acesse Configurações → Webhooks → [seu webhook] → Rotacionar Secret
- Copie o novo secret
- Atualize a variável de ambiente na sua aplicação
- Faça um deploy da sua aplicação
O Vistum passa a assinar com o novo secret imediatamente após a rotação.
Proteção contra replay
Implemente sempre a verificação de timestamp para rejeitar requisições antigas:
| Date.now() / 1000 - timestamp | > 300 → REJEITAR
Isso previne que um atacante reenvie uma requisição capturada anteriormente.