Ajuda / API e programadores
Webhooks de saída
Formato dos eventos enviados para os seus sistemas e como verificar a assinatura.
Formato
{
"event": "purchase.approved",
"id": "hotmart:HP123456789",
"app_id": "9b1f…",
"occurred_at": "2026-10-12T10:31:00.000Z",
"contact": {
"email": "ana@exemplo.pt",
"first_name": "Ana",
"last_name": "Silva",
"phone": null,
"consent": true,
"tags": [
"cliente"
]
},
"product_ids": [
"4c2e…"
],
"lesson_id": null,
"amount_cents": 9700,
"currency": "EUR",
"checkout_url": null,
"data": {}
}Cabeçalhos: X-Event (o tipo do evento), X-Signature (se definiu um segredo) e User-Agent: Zurian-Webhooks/1.0. O campo id é estável: use-o para ignorar entregas repetidas.
Verificar a assinatura
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody: string, header: string | null, secret: string) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
return !!header && header.length === expected.length &&
timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Calcule o HMAC sobre o corpo tal como chegou, antes de o converter de JSON.
Entregas e repetições
Responda com 2xx em menos de 15 segundos. Erros 5xx, 408, 429 e falhas de rede são repetidos com espera crescente; outros 4xx não. Os redirecionamentos não são seguidos e o URL tem de ser HTTPS público.
Eventos
| Evento | Quando |
|---|---|
member.joined | Novo aluno entrou na app |
purchase.approved | Compra aprovada |
access.revoked | Acesso retirado (reembolso/chargeback) |
lesson.completed | Aula concluída |
course.completed | Curso concluído |
quiz.passed | Quiz aprovado |
quiz.failed | Quiz reprovado |
member.inactive | Aluno inativo há X dias |
tag.added | Etiqueta adicionada |
checkout.abandoned | Carrinho abandonado |
payment.pending | Pagamento pendente (transferência, voucher ou referência) |
payment.failed | Pagamento recusado/expirado |
subscription.past_due | Subscrição com pagamento em atraso |
subscription.canceled | Subscrição cancelada |
subscription.plan_changed | Mudança de plano |
access.expiring | Acesso a terminar |
post.created | Publicação na comunidade |
funnel.completed | Quiz de captação concluído |